Дозвольте взяти реальний приклад для вирішення цього питання
Мені потрібно було обчислити середньозважену середню за моїми даними 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 секунд Пітон
0,23801879299935536 секунд SQL
У моїй базі даних 134000 підроблених записів OHLC, розділених на 1000 запасів, так що це приклад, коли SQL може перевершити ваш сервер додатків