Уявіть, що у вас є така структура таблиці:
LogId | ProductId | FromPositionId | ToPositionId | Date | Quantity
-----------------------------------------------------------------------------------
1 | 123 | 0 | 10002 | 2018-01-01 08:10:22 | 5
2 | 123 | 0 | 10003 | 2018-01-03 15:15:10 | 9
3 | 123 | 10002 | 10004 | 2018-01-07 21:08:56 | 3
4 | 123 | 10004 | 0 | 2018-02-09 10:03:23 | 1
FromPositionId
і ToPositionId
є біржовими позиціями. Наприклад, деякі позиції ID: s мають особливе значення, наприклад 0
. Подія від або до 0
означає, що запас був створений або вилучений. З 0
може бути запас від доставки і до 0
може бути відвантаженим замовленням.
Зараз ця таблиця містить близько 5,5 мільйонів рядків. Ми обчислюємо вартість запасів для кожного продукту і розміщуємо в таблиці кешу за графіком, використовуючи запит, який виглядає приблизно так:
WITH t AS
(
SELECT ToPositionId AS PositionId, SUM(Quantity) AS Quantity, ProductId
FROM ProductPositionLog
GROUP BY ToPositionId, ProductId
UNION
SELECT FromPositionId AS PositionId, -SUM(Quantity) AS Quantity, ProductId
FROM ProductPositionLog
GROUP BY FromPositionId, ProductId
)
SELECT t.ProductId, t.PositionId, SUM(t.Quantity) AS Quantity
FROM t
WHERE NOT t.PositionId = 0
GROUP BY t.ProductId, t.PositionId
HAVING SUM(t.Quantity) > 0
Хоча це завершується за розумну кількість часу (приблизно 20 секунд), я вважаю, що це досить неефективний спосіб розрахунку запасів. Ми рідко робимо що-небудь, крім INSERT
: s в цій таблиці, але іноді ми заносимо і регулюємо кількість або видаляємо рядок вручну через помилки людей, що генерують ці рядки.
У мене виникла ідея створити "контрольні точки" в окремій таблиці, обчислити значення до певного моменту та використовувати це як початкове значення при створенні нашої таблиці кеш-кількості запасів:
ProductId | PositionId | Date | Quantity
-------------------------------------------------------
123 | 10002 | 2018-01-07 21:08:56 | 2
Те, що ми іноді змінюємо рядки, створює проблему для цього, у цьому випадку ми також повинні пам’ятати, щоб видалити будь-яку контрольну точку, створену після зміни зміни журналу. Це можна вирішити, не розраховуючи контрольно-пропускні пункти до цього часу, але залишити місяць між тепер і останньою контрольною точкою (ми дуже рідко вносимо зміни, що давно назад).
Те, що нам іноді потрібно змінювати рядки, важко уникнути, і я хотів би, щоб це все-таки можна було зробити, це не показано в цій структурі, але події журналу іноді прив’язуються до інших записів в інших таблицях і додаються ще один рядок журналу отримати потрібну кількість іноді неможливо.
Таблиця журналів, як ви можете собі уявити, зростає досить швидко, а час для обчислення з часом лише збільшуватиметься.
Тож на моє запитання, як би ви вирішили це? Чи існує більш ефективний спосіб розрахунку поточної вартості акцій? Чи гарна моя ідея контрольно-пропускних пунктів?
Ми працюємо з веб-сервером SQL Server 2014 (12.0.5511)
План виконання: https://www.brentozar.com/pastetheplan/?id=Bk8gyc68Q
Я фактично вказав неправильний час виконання вище, 20-ті - це час повного оновлення кешу. Цей запит займає десь 6-10 секунд (8 секунд, коли я створив цей план запитів). У цьому запиті також є приєднання, якого не було в первісному питанні.