Hãy để tôi lấy một ví dụ thực tế để giải quyết câu hỏi này
Tôi cần tính trung bình di chuyển có trọng số trên dữ liệu ohlc của mình, tôi có khoảng 134000 cây nến với một biểu tượng cho mỗi cái để làm như vậy
- Tùy chọn 1 Thực hiện trong Python / Node, v.v.
- Tùy chọn 2 Thực hiện bằng chính SQL!
Cái nào tốt hơn?
- Về cơ bản, nếu tôi phải làm điều này bằng Python, tôi sẽ phải tìm nạp tất cả các bản ghi được lưu trữ ở mức tồi tệ nhất, thực hiện tính toán và lưu lại mọi thứ mà theo tôi là một sự lãng phí rất lớn của IO
- Thay đổi trung bình di chuyển có trọng số mỗi khi bạn nhận được một cây nến mới có nghĩa là tôi sẽ thực hiện một lượng lớn IO trong khoảng thời gian đều đặn không phải là ý kiến hay trong dấu hiệu của tôi
- Trong SQL, tất cả những gì tôi phải làm có lẽ là viết một trình kích hoạt tính toán và lưu trữ mọi thứ, do đó chỉ cần tìm nạp các giá trị WMA cuối cùng cho mỗi cặp mỗi giờ và điều đó hiệu quả hơn rất nhiều
Yêu cầu
- Nếu tôi phải tính toán WMA cho mỗi cây nến và lưu trữ nó, tôi sẽ làm điều đó trên Python
- Nhưng vì tôi chỉ cần giá trị cuối cùng, SQL nhanh hơn nhiều so với Python
Để khuyến khích bạn, đây là phiên bản Python để làm trung bình di chuyển có trọng số
WMA được thực hiện thông qua mã
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 thông qua 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()
Dù bạn có tin hay không, truy vấn sẽ chạy nhanh hơn phiên bản Pure Python khi thực hiện AVERAGE MOVING MOVING !!!Tôi đã từng bước viết ra truy vấn đó để chờ vào đó và bạn sẽ làm tốt
Tốc độ
0,42141127300055814 giây Python
0,23801879299935536 giây SQL
Tôi có 134000 bản ghi OHLC giả trong cơ sở dữ liệu của tôi được chia cho 1000 cổ phiếu để đó là một ví dụ về nơi SQL có thể vượt trội hơn máy chủ ứng dụng của bạn