Эффективная сумма скользящего окна по таблице базы данных - PullRequest
4 голосов
/ 13 января 2012

База данных имеет таблицу transactions со столбцами: account_id, date, transaction_value (целое число со знаком). В другой таблице (account_value) хранится текущая общая стоимость каждой учетной записи, которая представляет собой сумму всех transaction_value s для каждой учетной записи. Он обновляется с помощью триггера на таблице transactions (т. Е. INSERTs, UPDATEs и DELETEs для transactions запускают триггер для изменения account_value.)

Новым требованием является расчет общей суммы транзакции по счету только за последние 365 дней . Требуется только текущий промежуточный итог, а не предыдущие итоги. Это значение будет запрашиваться часто, почти так же часто, как account_value.

Как бы вы эффективно реализовали эту «сумму скользящих окон»? Новый стол в порядке. Есть ли способ избежать суммирования за годовой диапазон каждый раз?

Ответы [ 5 ]

1 голос
/ 13 января 2012

Это можно сделать с помощью стандартных оконных функций:

SELECT account_id,
       sum(transaction_value) over (partition by account_id order by date)
FROM transactions

order by внутри предложений over() делает сумму "скользящей".

Для «только последних 356 дней» вам потребуется второй запрос, который ограничит количество строк в предложении WHERE.

Вышеописанное работает в PostgreSQL, Oracle, DB2 и (я думаю) Teradata. SQL Server не поддерживает порядок в определении окна (в следующей версии Denali будет AFAIK)

1 голос
/ 13 января 2012

Если запросы к таблице транзакций выполняются чаще, чем вставки в таблицу транзакций, то, возможно, путь - это путь?

1 голос
/ 13 января 2012

Как все просто?

SELECT
   SUM(transaction_value), account_id
FROM
   transactions t
WHERE
   -- SQL Server, Sybase       t.DATE >= DATEADD(year, -1, GETDATE())
   -- MySQL            t.DATE >= DATE_SUB(NOW(), INTERVAL 12 MONTH)
GROUP BY
   account_id;

Возможно, вы захотите удалить компонент времени из выражений даты, используя DATE (MySQL) или таким образом в SQL Server

0 голосов
/ 13 января 2012

Я буду избегать любого реального SQL здесь, поскольку он сильно варьируется в зависимости от разнообразия используемого вами SQL.

Вы говорите, что у вас есть триггер для поддержания существующего промежуточного итога.

Я предполагаю, что он также (или, возможно, ночной процесс) создает новые ежедневные записи в таблице account_value.Затем операторы INSERT, UPDATE и DELETE запускают триггер, чтобы сложить или вычесть существующую промежуточную сумму?

Вам нужно только внести следующие изменения:
- добавить новое поле, year_value или что-то еще
- иметь существующее обновление триггера, которое аналогично существующему полю
- использовать тип ответа gbn для создания сегодняшних записей (или как бы далеко вы не задним числом)
- но инициализировать каждую новую ежедневную запись в несколько иномway ...

Когда вы вставляете новую строку для нового дня, она должна быть инициализирована как yesterday's value - the value 365 days ago.После этого поведение должно совпадать с тем, к чему вы уже привыкли.

0 голосов
/ 13 января 2012

Вам понадобится одноразовый сценарий для заполнения существующей таблицы значениями за предыдущий год для каждой существующей записи, который должен будет выполняться за весь предыдущий год для каждой сгенерированной записи.

После заполнения столбца скользящего года одной из альтернатив суммированию предыдущего года будет получение значения каждой новой записи в качестве значения скользящего года предыдущей записи, плюс значения транзакций с момента последнего обновления, минус значения транзакций междуза год до последнего обновления и год назад.

Я предлагаю попробовать оба подхода на основе реалистичных данных испытаний, чтобы увидеть, какие из них будут работать лучше - я ожидаю, что суммирование всего года будет выполнено, по крайней мере, там, гдеданные относительно скудны, в то время как разностный метод может работать лучше, если данные часто обновляются для каждой учетной записи.

...