T-SQL слишком дорогой запрос с выбором в / где / имеющим условие и составной первичный ключ - PullRequest
0 голосов
/ 16 мая 2018

Я создал http://www.sqlfiddle.com/#!18/f8137/2, чтобы показать вам схему

У меня есть три объекта "Счет-фактура" -> 1: n -> "Платеж" -> 1: n-> "Взятие "

У каждой сущности есть своя Общая сумма (сумма) и знак, который показывает, нужно ли мне добавлять или вычитать значение.

Проблема в том, что я не могу найти эффективный способ«ВЫБРАТЬ» мои счета-фактуры с открытым счетом (сумма выручки отличается от суммы счета-фактуры).У меня есть тысячи записей, и эти два выбора требуют много времени для выполнения (от 25 до 30 секунд).

Здесь создание схемы

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_year    invoice_number  amount  sign
2018            1               100.2   1
2018            2               98.4    1

Оплата

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_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_code   sign_value  description
1           1           CREDIT
2           -1          DEBT

Это запросы, которые я написал

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

Кроме того, у этих сущностей есть составные первичные ключи, и я должен использовать их с доктриной и knp-paginator-bundle, поэтому ядолжен "СЧИТАТЬ" число строк

Есть идеи, как улучшить хотя бы время выполнения?

Ответы [ 2 ]

0 голосов
/ 16 мая 2018

Попробуйте группу по

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
0 голосов
/ 16 мая 2018

Ваш запрос игнорирует Payment table.Вам необходимо убедиться, что записи во внешнем 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;

Без добавления этой части в ваш запрос, запрос был явно неверным иисполняется много времени.Кроме того, я рекомендую не использовать оператор * в предложениях SELECT, поскольку они могут быть небезопасными (например, при наличии поля password) и ухудшать производительность (если есть column, который содержит очень большие данныечто вам не нужно в этом случае).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...