简体   繁体   English

T-SQL查询过于昂贵,在何处/具有条件和复合主键中进行选择

[英]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一起使用,因此我必须“计数”行数

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM