Представьте, что у вас есть следующая структура таблицы:
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
позиции на складе. Например, некоторые идентификаторы позиции имеют особое значение 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 Web (12.0.5511)
План выполнения: https://www.brentozar.com/pastetheplan/?id=Bk8gyc68Q
Я фактически указал неверное время выполнения выше, 20 с - это время, которое потребовалось для полного обновления кэша. Этот запрос занимает где-то около 6-10 секунд (8 секунд, когда я создал этот план запроса). В этом запросе также есть соединение, которого не было в исходном вопросе.