Оптимизация поиска транзакций по критериям внутри динамический диапазонов (window) для исторических данных с последующей аггрегацией
Ниже приведен рабочие запросы, которые хотелось бы оптимизировать по производительность для mssql 2019 Решаемая задача.
- В исторических данных trades требуется найти все возможные пары транзакций, которые могут находиться друг от друга на растоянии не более @shot_period (в милисекунд)
- Внутри диапазона все цены (price) идущие после первой/начальной транзакции включительно до конечной (минимальной/искомой) - должны быть меньше первой транзакции. price1 > price2, price1 > price3, price1 > price4, etc
- Искомая/минимальная транзакция имеет наименьшее значение внутри заданного временного диапазона (@shot_period) min(priceN)
- Процентное сотношение цен первой и минимальной транзакции должно быть больше или равно @min_percent
100*((price1/priceN)-1) > @min_percent - Для случаев когда может быть несколько пар транзакций, с разными начальными tid (tid1), но с одинаковыми минимальными tid (tid2), береться только первая пара с самой ранней tid (tid1)
- Для транзакций внутри каждой найденой пары, нужно подсчитать sum(cost), sum(amount), count(*)
DECLARE @shot_period INT = 5000; --(milisseconds)
DECLARE @min_percent FLOAT = 1;
--pair - 'ETH/BTC', 'LTC/BTC', ....
--tid - transaction id
--ts - timestamp (milliseconds)
--dt - datetime
-- Insert statements for procedure here
SELECT a.pair,
a.tid tid1,
a.ts ts1,
a.dt dt1,
a.price price1,
c.tid tid2,
c.ts ts2,
c.dt dt2,
c.price price2,
ROUND(100*((a.price/c.price) - 1),4) shotPercent
INTO #tmp1
FROM trades a WITH(NOLOCK, NOWAIT) CROSS APPLY(
SELECT TOP(1) b.tid, b.ts, b.dt, b.price
FROM trades b WITH(NOLOCK, NOWAIT)
WHERE b.pair = a.pair
AND b.ts BETWEEN a.ts and a.ts + @shot_period
AND b.tid > a.tid
ORDER BY b.price, b.tid
) c
WHERE ROUND(100*((a.price/c.price) - 1),4) >= @min_percent
SELECT r.pair, r.tid1, r.ts1, r.dt1, r.price1, r.tid2, r.ts2, r.dt2, r.price2, r.shotPercent, COUNT(*) shotTrades, MAX(CASE WHEN t.tid = r.tid1 THEN 0 ELSE t.price END) maxPrice, SUM(t.amount) shotAmount, sum(t.cost) shotCost
INTO #tmp1a
FROM #tmp1 r WITH(NOLOCK, NOWAIT) INNER HASH JOIN trades t WITH(NOLOCK, NOWAIT) ON t.pair = r.pair AND t.ts BETWEEN r.ts1 AND r.ts2 AND t.tid BETWEEN r.tid1 AND r.tid2
GROUP BY r.pair, r.tid1, r.ts1, r.dt1, r.price1, r.tid2, r.ts2, r.dt2, r.price2, r.shotPercent
HAVING MAX(CASE WHEN t.tid = r.tid1 THEN 0 ELSE t.price END) < r.price1
DROP TABLE #tmp1;
CREATE CLUSTERED INDEX t1a ON #tmp1a(pair, tid2, tid1);
SELECT pair, CAST(q.dt1 AS DATE) as [date], tid1, ts1, dt1, price1, tid2, ts2, dt2, price2, shotPercent, shotTrades, shotAmount, shotCost
INTO #tmp2
FROM (
SELECT pair, tid1, ts1, dt1, price1, tid2, ts2, dt2, price2, shotPercent, shotTrades, shotAmount, shotCost, ROW_NUMBER() OVER(PARTITION BY pair, tid2 ORDER BY tid1) rn
FROM #tmp1a WITH(NOLOCK, NOWAIT)
) q
WHERE rn = 1