[英]T-SQL too expensive query with select in where/having condition and composite primary key
I've created an http://www.sqlfiddle.com/#!18/f8137/2 to show you the schema 我创建了一个http://www.sqlfiddle.com/#!18/f8137/2为您显示架构
I have three entities "Invoice"->1:n->"Payment"->1:n->"Taking" 我有三个实体:“发票”-> 1:n->“付款”-> 1:n->“收款”
Each entity has it's own Total (amount) and a sign that shows if i have to add or subtract a value. 每个实体都有自己的总计(金额)和一个符号,显示我是否必须加或减一个值。
The problem is that i can't find an efficient way to "SELECT" my invoices that have an open bill (the sum of takings differs from the amount of the invoice). 问题是我找不到有效的方法来“选择”具有未结清发票的发票(收取的总金额与发票金额不同)。 I have thousands of records and these two selects take a lot of time to be executed (from 25 to 30 seconds). 我有成千上万的记录,这两个选择要花很多时间(从25到30秒)。
Here the creation of the schema 在这里创建模式
CREATE TABLE Sign (
sign_code INT NOT NULL IDENTITY(1,1),
sign_value INT NOT NULL,
description VARCHAR(255) NOT NULL,
PRIMARY KEY (sign_code)
);
CREATE TABLE Invoice (
invoice_year int NOT NULL,
invoice_number int NOT NULL,
amount DECIMAL(10,2) NOT NULL,
sign INT NOT NULL,
PRIMARY KEY (invoice_year, invoice_number) ,
FOREIGN KEY (sign) REFERENCES Sign(sign_code)
);
CREATE TABLE Payment (
invoice_year int NOT NULL,
invoice_number int NOT NULL,
payment_row int NOT NULL,
amount DECIMAL(10,2) NOT NULL,
sign INT NOT NULL,
PRIMARY KEY (invoice_year, invoice_number, payment_row),
FOREIGN KEY (invoice_year, invoice_number) REFERENCES Invoice(invoice_year, invoice_number),
FOREIGN KEY (sign) REFERENCES Sign(sign_code)
);
CREATE TABLE Taking (
taking_year int NOT NULL,
taking_row INT NOT NULL,
invoice_year int NOT NULL,
invoice_number int NOT NULL,
payment_row int NOT NULL,
amount DECIMAL(10,2) NOT NULL,
sign INT NOT NULL,
PRIMARY KEY (taking_year, taking_row),
FOREIGN KEY (invoice_year, invoice_number, payment_row) REFERENCES Payment(invoice_year, invoice_number, payment_row),
FOREIGN KEY (invoice_year, invoice_number) REFERENCES Invoice(invoice_year, invoice_number),
FOREIGN KEY (sign) REFERENCES Sign(sign_code)
);
Invoice 发票
invoice_year invoice_number amount sign
2018 1 100.2 1
2018 2 98.4 1
Payment 付款
invoice_year invoice_number payment_row amount sign
2018 1 1 50 1
2018 1 2 50.2 1
2018 2 1 90.4 1
2018 2 2 8 1
Taking 服用
taking_year taking_row invoice_year invoice_number payment_row amount sign
2018 1 2018 1 1 80 1
2018 2 2018 1 1 80 2
2018 3 2018 1 1 25 1
2018 4 2018 1 1 25 1
2018 5 2018 1 2 25.1 1
2018 6 2018 1 2 24.1 1
2018 7 2018 2 1 90.4 1
2018 8 2018 2 2 8 1
Sign 标志
sign_code sign_value description
1 1 CREDIT
2 -1 DEBT
These are the queries i've wrote 这些是我写的查询
SELECT COUNT(*)
FROM Invoice AS I
INNER JOIN Sign S1 ON I.sign = S1.sign_code
WHERE I.amount*S1.sign_value - (SELECT SUM(T.amount*S2.sign_value)
FROM Taking T
INNER JOIN Sign S2 ON T.sign = S2.sign_code
WHERE T.invoice_year = I.invoice_year AND T.invoice_number = I.invoice_number
) <> 0;
SELECT I.*
FROM Invoice AS I
INNER JOIN Sign S1 ON I.sign = S1.sign_code
WHERE I.amount*S1.sign_value - (SELECT SUM(T.amount*S2.sign_value)
FROM Taking T
INNER JOIN Sign S2 ON T.sign = S2.sign_code
WHERE T.invoice_year = I.invoice_year AND T.invoice_number = I.invoice_number
) <> 0
Also, these entities have composite primary keys and i have to use with doctrine and knp-paginator-bundle so i have to "COUNT" the number of rows 另外,这些实体具有复合主键,我必须与doctrine和knp-paginator-bundle一起使用,因此我必须“计数”行数
https://github.com/doctrine/doctrine2/issues/2910 https://github.com/doctrine/doctrine2/issues/2910
Single id is not allowed on composite primary key in entity using knp paginator 使用KNP分页器的实体中的复合主键上不允许使用单个ID
Any idea on how to improve at least the execution time? 关于如何至少缩短执行时间的任何想法吗?
Your query ignores the Payment
table
. 您的查询将忽略Payment
table
。 You will need to make sure that the records in the outer select
are matched against the records in the inner select
: 您将需要确保外部select
中的记录与内部select
中的记录匹配:
SELECT I.*
FROM Invoice AS I
INNER JOIN Sign S1 ON I.sign = S1.sign_code
WHERE I.amount*S1.sign_value - (SELECT SUM(T.amount*S2.sign_value)
FROM Taking T
INNER JOIN Payment P ON T.invoice_year = P.invoice_year and T.invoice_number = P.invoice_number and T.payment_row = P.payment_row and P.invoice_year = I.invoice_year and P.invoice_number = I.invoice_number
INNER JOIN Sign S2 ON T.sign = S2.sign_code
) <> 0;
Without this part added to your query, the query was obviously incorrect and takes a lot of time to be executed. 如果没有将这部分添加到查询中,则该查询显然是不正确的,并且需要大量时间才能执行。 Also, I recommend not using the *
operator in SELECT clauses, as they might be unsafe (if there is a password
field, for instance) and bad for performance (if there is a column
which holds very large data which is unnecessary for you in this case). 另外,我建议不要在SELECT子句中使用*
运算符,因为它们可能不安全(例如,如果有password
字段)并且对性能不利(如果有一个column
包含非常大的数据,而这对于您来说是不必要的)这个案例)。
Try a group by 尝试一组
SELECT COUNT(*)
FROM Invoice AS I
JOIN Sign S1
ON I.sign = S1.sign_code
JOIN ( SELECT T.invoice_year, T.invoice_number
, SUM(T.amount*S2.sign_value) as sm
FROM Taking T
JOIN Sign S2
GROUP BY T.invoice_year, T.invoice_number
) t
ON T.invoice_year = I.invoice_year
AND T.invoice_number = I.invoice_number
AND I.amount*S1.sign_value <> t.sm
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.