Позвольте мне привести реальный пример, чтобы ответить на этот вопрос
Мне нужно было рассчитать взвешенное скользящее среднее на моих данных по Ohlc, у меня есть около 134000 свечей с символом для каждой из них
- Вариант 1 Сделайте это в Python / Node и т. Д.
- Вариант 2 Сделайте это в самом SQL!
Какой из них лучше?
- Если бы мне пришлось делать это в Python, по сути, мне пришлось бы извлекать все сохраненные записи в худшем случае, выполнять вычисления и сохранять все обратно, что, на мой взгляд, является огромной потерей IO
- Взвешенное скользящее среднее меняется каждый раз, когда вы получаете новую свечу, что означает, что я буду делать огромное количество операций ввода-вывода через регулярные промежутки времени, что не является
хорошее мнение в моем знаке
- В SQL все, что мне нужно сделать, это, вероятно, написать триггер, который вычисляет и хранит все, поэтому время от времени требуется только извлекать окончательные значения WMA для каждой пары, и это намного эффективнее
Требования
- Если бы мне нужно было рассчитать WMA для каждой свечи и сохранить ее, я бы сделал это на Python
- Но так как мне нужно только последнее значение, SQL намного быстрее, чем Python
Чтобы поддержать вас, это версия Python для взвешенного скользящего среднего
WMA через код
import psycopg2
import psycopg2.extras
from talib import func
import timeit
import numpy as np
with psycopg2.connect('dbname=xyz user=xyz') as conn:
with conn.cursor() as cur:
t0 = timeit.default_timer()
cur.execute('select distinct symbol from ohlc_900 order by symbol')
for symbol in cur.fetchall():
cur.execute('select c from ohlc_900 where symbol = %s order by ts', symbol)
ohlc = np.array(cur.fetchall(), dtype = ([('c', 'f8')]))
wma = func.WMA(ohlc['c'], 10)
# print(*symbol, wma[-1])
print(timeit.default_timer() - t0)
conn.close()
WMA Через SQL
"""
if the period is 10
then we need 9 previous candles or 15 x 9 = 135 mins on the interval department
we also need to start counting at row number - (count in that group - 10)
For example if AAPL had 134 coins and current row number was 125
weight at that row will be weight = 125 - (134 - 10) = 1
10 period WMA calculations
Row no Weight c
125 1
126 2
127 3
128 4
129 5
130 6
131 7
132 8
133 9
134 10
"""
query2 = """
WITH
condition(sym, maxts, cnt) as (
select symbol, max(ts), count(symbol) from ohlc_900 group by symbol
),
cte as (
select symbol, ts,
case when cnt >= 10 and ts >= maxts - interval '135 mins'
then (row_number() over (partition by symbol order by ts) - (cnt - 10)) * c
else null
end as weighted_close
from ohlc_900
INNER JOIN condition
ON symbol = sym
WINDOW
w as (partition by symbol order by ts rows between 9 preceding and current row)
)
select symbol, sum(weighted_close)/55 as wma
from cte
WHERE weighted_close is NOT NULL
GROUP by symbol ORDER BY symbol
"""
with psycopg2.connect('dbname=xyz user=xyz') as conn:
with conn.cursor() as cur:
t0 = timeit.default_timer()
cur.execute(query2)
# for i in cur.fetchall():
# print(*i)
print(timeit.default_timer() - t0)
conn.close()
Хотите верьте, хотите нет, запрос выполняется быстрее, чем версия Pure Python для выполнения ВЕСОВЕДНОГО СРЕДНЕГО ДВИЖЕНИЯ !!! Я пошёл шаг за шагом к написанию этого запроса, так что подождите, и вы просто выполните прекрасный
Скорость
0,42141127300055814 секунд Python
0,23801879299935536 секунд SQL
У меня в базе данных 134000 фальшивых записей OHLC, поделенных на 1000 акций, так что это пример того, как SQL может превзойти ваш сервер приложений