Apa pro dan kontra dari melakukan perhitungan dalam sql vs di aplikasi Anda

154

shopkeeper tabel memiliki bidang berikut:

id (bigint),amount (numeric(19,2)),createddate (timestamp)

Katakanlah, saya memiliki tabel di atas. Saya ingin mendapatkan catatan untuk kemarin dan menghasilkan laporan dengan memiliki jumlah yang dicetak ke sen.

Salah satu caranya adalah dengan melakukan perhitungan dalam aplikasi java saya dan menjalankan kueri sederhana

Date previousDate ;// $1 calculate in application

Date todayDate;// $2 calculate in application

select amount where createddate between $1 and $2 

dan kemudian mengulangi catatan dan mengonversi jumlah menjadi sen dalam aplikasi java saya dan menghasilkan laporan

Cara lain adalah seperti melakukan perhitungan dalam kueri sql itu sendiri:

select cast(amount * 100 as int) as "Cents"
from shopkeeper  where createddate  between date_trunc('day', now()) - interval '1 day'  and  date_trunc('day', now())

dan kemudian mengulangi catatan dan menghasilkan laporan

Dalam satu cara, semua pemrosesan saya dilakukan dalam aplikasi java dan permintaan sederhana diaktifkan. Dalam kasus lain, semua konversi dan perhitungan dilakukan dalam permintaan Sql.

Kasus penggunaan di atas hanyalah sebuah contoh, dalam skenario nyata sebuah tabel dapat memiliki banyak kolom yang memerlukan pemrosesan yang serupa.

Bisakah Anda memberi tahu saya pendekatan mana yang lebih baik dalam hal kinerja dan aspek lainnya dan mengapa?

hellojava
sumber
2
Perhitungan tanggal tidak akan berpengaruh sama sekali - dengan asumsi mesin sql Anda memang akan menghitung tanggal hanya sekali. memiliki mereka didefinisikan dalam aplikasi Anda masuk akal, karena mereka akan didefinisikan di sana pada titik tertentu, baik itu untuk judul laporan atau hal-hal lain. mengalikan nilai dengan 100 dalam hal ini bisa dilakukan pada tingkat mana pun, karena Anda tetap akan mengulangi baris-baris itu untuk rendering dan * 100 tidak mungkin lebih lambat di tingkat mana pun kecuali front-end. Dalam kedua kasus, perhitungan Anda minimal dan dikerdilkan oleh operasi di sekitarnya, bukan masalah kinerja.
Morg.

Jawaban:

206

Itu tergantung pada banyak faktor - tetapi yang paling penting:

  • kompleksitas perhitungan (lebih melakukan berderak kompleks pada aplikasi-server, karena itu sisik keluar , melainkan dari server db, yang skala up )
  • volume data (jika Anda perlu mengakses / menggabungkan banyak data, melakukannya di server db akan menghemat bandwidth, dan disk io jika agregat dapat dilakukan di dalam indeks)
  • kenyamanan (sql bukan bahasa terbaik untuk pekerjaan kompleks - terutama tidak bagus untuk pekerjaan prosedural, tetapi sangat baik untuk pekerjaan berbasis set; penanganan kesalahan yang buruk, meskipun)

Seperti biasa, jika Anda melakukan membawa kembali data ke aplikasi-server, meminimalkan kolom dan baris akan untuk keuntungan Anda. Memastikan kueri disetel dan diindeks dengan tepat akan membantu skenario mana pun.

Perhatikan kembali catatan Anda:

dan kemudian mengulangi catatan

Looping melalui catatan hampir selalu merupakan hal yang salah untuk dilakukan dalam sql - menulis operasi berbasis set lebih disukai.

Sebagai aturan umum , saya lebih memilih untuk menjaga pekerjaan database seminimal mungkin "simpan data ini, ambil data ini" - namun, selalu ada contoh skenario di mana kueri elegan di server dapat menghemat banyak bandwidth.

Juga pertimbangkan: jika ini mahal secara komputasi, dapatkah itu di-cache di suatu tempat?

Jika Anda menginginkan "yang lebih baik" yang akurat ; buat kode baik dan bandingkan (perhatikan bahwa draf pertama dari keduanya kemungkinan tidak 100% disetel). Tetapi faktor dalam penggunaan khas untuk itu: jika, pada kenyataannya, itu disebut 5 kali (secara terpisah) sekaligus, maka simulasikan bahwa: jangan membandingkan hanya satu "1 dari ini vs 1 dari mereka".

Marc Gravell
sumber
Looping melibatkan lebih banyak atau lebih sedikit pemrosesan "row-at-a-time". Dan itu berarti 2 * latensi jaringan plus empat konteks beralih pulang pergi. Ya: itu mahal. Operasi DBMS "asli" melakukan semua kerja keras untuk meminimalkan disk-I / O (panggilan sistem) tetapi berhasil mengambil lebih dari satu baris per panggilan sistem. Row sekaligus membutuhkan setidaknya empat panggilan sistem.
wildplasser
@wildplasser tidak perlu; server bisa berupa streaming baris yang Anda konsumsi saat tiba - metafora "pembaca" tidak jarang.
Marc Gravell
1
@ Mark Cavell: Yah, itu tergantung. Dalam kasus di mana tapak program aplikasi hanya satu catatan logis, itu kurang lebih baik. Tetapi sebagian besar "kerangka kerja" yang saya tahu cenderung menyedot semua catatan saat startup, dan memecat mereka, satu per satu. Mengunci adalah perangkap lain.
wildplasser
Saya pikir aturan praktis yang baik adalah: jangan membawa kembali dari baris SQL server data yang pada akhirnya tidak Anda butuhkan. Misalnya, jika Anda harus melakukan operasi agregat, mereka kemungkinan termasuk dalam SQL. Bergabung di antara tabel atau subquery? SQL Itu juga pendekatan yang kami gunakan dengan lencana, dan, sejauh ini, kami menghadapi skala :-)
Sklivvz
1
@zinking itu akan menjadi operasi berbasis set. Dalam skenario itu Anda tidak menulis kode loop - itu adalah detail implementasi. Yang saya maksud dengan "looping" adalah loop eksplisit, misalnya kursor
Marc Gravell
86

Biarkan saya menggunakan metafora: jika Anda ingin membeli kalung emas di Paris, tukang emas bisa duduk di Cape Town atau Paris, itu adalah masalah keterampilan dan selera. Tetapi Anda tidak akan pernah mengirim berton-ton bijih emas dari Afrika Selatan ke Prancis untuk itu. Bijih diproses di lokasi penambangan (atau setidaknya di area umum), hanya emas yang dikirim. Hal yang sama harus berlaku untuk aplikasi dan database.

Sejauh menyangkut PostgreSQL , Anda dapat melakukan hampir semua hal di server, cukup efisien. RDBMS unggul dalam pertanyaan kompleks. Untuk kebutuhan prosedural, Anda dapat memilih dari berbagai bahasa skrip sisi server : tcl, python, perl, dan banyak lagi. Namun, kebanyakan saya menggunakan PL / pgSQL .

Skenario kasus terburuk adalah berulang kali pergi ke server untuk setiap baris satu set yang lebih besar. (Itu akan seperti pengiriman satu ton bijih sekali.)

Baris kedua , jika Anda mengirim sejumlah permintaan, masing-masing bergantung pada yang sebelumnya, sementara semua itu bisa dilakukan dalam satu permintaan atau prosedur di server. (Itu seperti mengirim emas, dan masing-masing permata dengan kapal terpisah, secara berurutan.)

Bolak-balik antara aplikasi dan server itu mahal. Untuk server dan klien. Cobalah untuk mengurangi itu, dan Anda akan menang - ergo: gunakan prosedur sisi server dan / atau SQL canggih jika perlu.

Kami baru saja menyelesaikan sebuah proyek di mana kami mengemas hampir semua permintaan kompleks ke dalam fungsi Postgres. Aplikasi menyerahkan parameter dan mendapatkan set data yang dibutuhkan. Cepat, bersih, sederhana (untuk pengembang aplikasi), I / O dikurangi menjadi minimum ... kalung berkilau dengan jejak karbon rendah.

Erwin Brandstetter
sumber
12
Saya akan berhati-hati menggunakan analogi ini untuk membuat keputusan desain yang berarti dengan pengembang lain. Analogi lebih merupakan perangkat retoris daripada logis. Di antara faktor-faktor lain, jauh lebih murah untuk mengirimkan data ke server aplikasi daripada mengirim bijih emas ke tukang emas.
Doug
3
Anda akan mengirim bijih atau emas tergantung dari apa yang lebih murah, jika Anda tidak memiliki teknologi untuk mengubah bijih menjadi emas, atau harganya menjadi mahal (karena penambang ingin membunuh pekerja lain ini), Anda akan mengirimkannya ke lokasi lain, mungkin di antara tukang emas dan penambang, terutama jika Anda memiliki lebih dari satu tukang emas.
Dainius
1
persis apa yang saya setuju, saya tidak berpikir itu selalu hal yang buruk untuk melakukan perhitungan berbasis loop di SQL @a_horse_with_no_name, kadang-kadang ini harus dilakukan, saya lebih suka dihitung ketika data diambil seperti yang ditunjukkan oleh metafora Erwin. atau Anda harus mengulang ini dengan biaya ketika data diambil kembali.
zinking
-1 Karena ini argumen satu sisi, mengabaikan trade-off, dan membuat orang bodoh untuk pihak lawan alih-alih mempertimbangkan dan menyangkal kasus terbaik dari pihak lawan. "Bolak-balik antara aplikasi dan server itu mahal" - tentu saja: tetapi bukan satu-satunya hal yang mahal, dan berbagai biaya harus ditimbang satu sama lain. Mungkin ternyata pertanyaan "SQL canggih" atau prosedur tersimpan adalah yang terbaik untuk kasus tertentu; tetapi perincian kasus ini umumnya harus diperhitungkan ketika membuat tekad semacam itu.
yfeldblum
Analogi keren tapi sayangnya ini didasarkan pada asumsi yang salah. Pengiriman bijih emas sangat umum. Rasio pengupasan emas adalah sekitar 1: 1 (emas menjadi limbah) namun seringkali lebih murah untuk memprosesnya di luar lokasi, di mana peralatan dan kualitas pengerjaan yang lebih baik tersedia. Bergantung pada ukuran pengiriman, meningkatkan efisiensi pemrosesan sebesar 0,1% dapat memungkinkan peningkatan relatif dari pendapatan (meskipun harga pengiriman berlipat ganda) - karena emas cukup mahal akhir-akhir ini. Bijih lain, seperti besi misalnya biasanya juga dikirimkan (rasio pengupasan besi sekitar 60%!).
Chris Koston
18

Dalam hal ini Anda mungkin sedikit lebih baik melakukan perhitungan dalam SQL karena mesin database cenderung memiliki rutinitas aritmatika desimal yang lebih efisien daripada Java.

Meskipun untuk perhitungan level baris secara umum tidak ada banyak perbedaan.

Di mana itu membuat perbedaan adalah:

  • Perhitungan agregat seperti SUM (), AVG (), MIN (), MAX () di sini mesin basis data akan menjadi urutan besarnya lebih cepat daripada implementasi Java.
  • Di mana saja perhitungan digunakan untuk memfilter baris. Memfilter pada DB jauh lebih efisien daripada membaca satu baris dan kemudian membuangnya.
James Anderson
sumber
12

Tidak ada hitam / putih sehubungan dengan bagian apa dari logika akses data yang harus dilakukan dalam SQL dan bagian apa yang harus dilakukan dalam aplikasi Anda. Saya suka kata - kata Mark Gravell , yang membedakannya

  • perhitungan yang rumit
  • perhitungan intensif data

Kekuatan dan ekspresifitas SQL sangat diremehkan. Sejak diperkenalkannya fungsi jendela , banyak perhitungan berorientasi non-ketat dapat dilakukan dengan sangat mudah dan elegan dalam database.

Tiga aturan praktis harus selalu diikuti, terlepas dari keseluruhan arsitektur aplikasi:

  • jaga agar jumlah data yang ditransfer antara database dan aplikasi ramping (mendukung penghitungan hal-hal dalam DB)
  • jaga agar jumlah data yang dimuat dari disk oleh database tetap ramping (demi memungkinkan database mengoptimalkan pernyataan untuk menghindari akses data yang tidak perlu)
  • jangan mendorong basis data ke batas CPU-nya dengan perhitungan yang rumit dan bersamaan (demi menarik data ke dalam memori aplikasi dan melakukan perhitungan di sana)

Dalam pengalaman saya, dengan DBA yang layak dan beberapa pengetahuan yang layak tentang database yang layak Anda, Anda tidak akan mengalami keterbatasan CPU DBs Anda segera.

Beberapa bacaan lebih lanjut di mana hal-hal ini dijelaskan:

Lukas Eder
sumber
2

Secara umum melakukan hal-hal dalam SQL jika ada kemungkinan juga modul atau komponen lain dalam proyek yang sama atau lainnya perlu mendapatkan hasil tersebut. operasi atom yang dilakukan sisi server juga lebih baik karena Anda hanya perlu memanggil proc yang tersimpan dari alat manajemen db untuk mendapatkan nilai akhir tanpa proses lebih lanjut.

Dalam beberapa kasus ini tidak berlaku tetapi ketika itu masuk akal. juga secara umum kotak db memiliki perangkat keras dan kinerja terbaik.

Davide Piras
sumber
Dapat digunakan kembali dapat hadir di tingkat mana pun dan bukan alasan (kinerja bijaksana) untuk menempatkan lebih banyak perhitungan dalam SQL. "Secara umum kotak db": ini salah dan lebih jauh, seperti yang dikatakan marc gravell, penskalaan tidak bekerja dengan cara yang sama. Sebagian besar database memerlukan sedikit perangkat keras untuk dijalankan dengan baik, dan pola kinerja tidak ada hubungannya dengan yang ada pada aplikasi server (yaitu saya akan menghabiskan 2 / 3rds anggaran saya untuk server SQL pada IO seperti dewa sedangkan saya tidak akan menghabiskan lebih banyak dari beberapa ratus untuk tumpukan penyimpanan appserver).
Morg.
1

Jika Anda menulis di atas ORM atau menulis aplikasi kasual berkinerja rendah, gunakan pola apa pun yang menyederhanakan aplikasi. Jika Anda menulis aplikasi berkinerja tinggi dan memikirkan skala, Anda akan menang dengan memindahkan pemrosesan ke data. Saya sangat menganjurkan untuk memindahkan pemrosesan ke data.

Mari kita pikirkan tentang ini dalam dua langkah: (1) transaksi OLTP (jumlah kecil catatan). (2) OLAP (pemindaian panjang banyak catatan).

Dalam kasus OLTP, jika Anda ingin cepat (10k - 100k transaksi per detik), Anda harus menghapus kait, kunci, dan pertikaian kunci mati dari database. Ini berarti bahwa Anda perlu menghilangkan warung panjang dalam transaksi: perjalanan pulang-pergi dari klien ke DB untuk memindahkan pemrosesan ke klien adalah salah satu kios yang sangat panjang. Anda tidak dapat memiliki transaksi lama (untuk membuat baca / perbarui atom) dan memiliki throughput yang sangat tinggi.

Re: penskalaan horizontal. Skala basis data modern secara horizontal. Sistem-sistem tersebut sudah menerapkan HA dan toleransi kesalahan. Manfaatkan itu dan cobalah untuk menyederhanakan ruang aplikasi Anda.

Mari kita lihat OLAP - dalam hal ini jelas bahwa menyeret kemungkinan terrabytes data kembali ke aplikasi adalah ide yang mengerikan. Sistem-sistem ini dibangun secara khusus untuk beroperasi dengan sangat efisien terhadap data kolom yang terkompresi dan disusun sebelumnya. Sistem OLAP modern juga skala secara horizontal dan memiliki perencana kueri canggih yang menyebarkan pekerjaan secara horizontal (secara internal memindahkan pemrosesan ke data).

Ryan
sumber
0

Apakah akan melakukan perhitungan di ujung depan atau di backend sangat diputuskan jika kita dapat menentukan tujuan kita dalam implementasi bisnis. Pada saat kode java mungkin berkinerja lebih baik daripada kode sql baik ditulis dengan baik atau mungkin sebaliknya. Tapi tetap saja jika bingung Anda bisa mencoba menentukan terlebih dahulu -

  1. Jika Anda dapat mencapai sesuatu secara langsung melalui database sql maka lebih baik lakukan karena db akan melakukan jauh lebih baik dan melakukan perhitungan di sana dan kemudian dengan hasil fetch. Namun jika perhitungan sebenarnya membutuhkan terlalu banyak perhitungan dari sana-sini maka Anda bisa menggunakan kode aplikasi. Mengapa? Karena skenario seperti perulangan dalam kebanyakan kasus tidak ditangani dengan baik oleh sql dimana bahasa front end lebih baik dirancang untuk hal-hal ini.
  2. Dalam hal perhitungan serupa diperlukan dari banyak tempat maka jelas menempatkan kode perhitungan di ujung db akan lebih baik untuk menjaga hal-hal di tempat yang sama.
  3. Jika ada banyak perhitungan yang harus dilakukan untuk mencapai hasil akhir melalui banyak pertanyaan yang berbeda maka gunakan juga db akhir karena Anda dapat menempatkan kode yang sama dalam prosedur tersimpan untuk melakukan lebih baik daripada mengambil hasil dari backend dan kemudian menghitungnya di depan akhir.

Ada banyak aspek lain yang dapat Anda pikirkan sebelum Anda memutuskan di mana menempatkan kode. Satu persepsi benar-benar salah - Semuanya dapat dilakukan terbaik di Jawa (kode aplikasi) dan / atau semuanya terbaik dilakukan oleh db (kode sql).

Neo
sumber
0

Membentuk sudut pandang kinerja: Ini adalah operasi aritmatika yang sangat sederhana yang hampir pasti dapat dilakukan jauh lebih cepat daripada benar-benar mengambil data dari disk yang menjadi basis data. Juga, menghitung nilai-nilai di mana klausa cenderung sangat cepat pada setiap runtime. Singkatnya, bottleneck harus disk IO, bukan perhitungan nilai.

Sesuai keterbacaan, saya pikir jika Anda menggunakan ORM Anda harus melakukannya di lingkungan server aplikasi Anda, karena ORM akan memungkinkan Anda bekerja dengan data yang mendasarinya dengan sangat mudah, menggunakan operasi berbasis set. Jika Anda akan menulis SQL mentah, tidak ada yang salah dengan melakukan perhitungan di sana, SQL Anda juga akan terlihat sedikit lebih bagus dan lebih mudah dibaca jika diformat dengan benar.

Johannes Gehrs
sumber
0

Yang terpenting, "kinerja" tidak didefinisikan.

Yang paling penting bagi saya adalah waktu pengembang.

Tulis kueri SQL. Jika terlalu lambat atau DB menjadi hambatan, maka pertimbangkan kembali. Pada saat itu, Anda dapat membandingkan dua pendekatan dan membuat keputusan berdasarkan data nyata yang relevan dengan pengaturan Anda (perangkat keras dan tumpukan apa pun yang Anda gunakan).

pengguna2757750
sumber
0

Saya tidak percaya perbedaan kinerja dapat dipikirkan tanpa contoh dan tolok ukur tertentu, tetapi saya harus mengambil lagi:

Mana yang bisa Anda pertahankan lebih baik? Misalnya, Anda mungkin ingin mengalihkan front-end Anda dari Java ke Flash, atau HTML5, atau C ++, atau yang lainnya. Sejumlah besar program telah melalui perubahan seperti itu, atau bahkan ada dalam lebih dari satu bahasa untuk memulai, karena mereka perlu bekerja pada beberapa perangkat.

Bahkan jika Anda memiliki lapisan tengah yang tepat (dari contoh yang diberikan, sepertinya bukan itu masalahnya), lapisan itu mungkin berubah dan JBoss mungkin menjadi Ruby / Rails.

Di sisi lain, tidak mungkin bahwa Anda akan mengganti SQL-backend dengan sesuatu yang bukan DB relasional dengan SQL dan bahkan jika Anda melakukannya, Anda harus menulis ulang front-end dari awal, jadi intinya adalah dapat diperdebatkan.

Gagasan saya adalah jika Anda melakukan perhitungan dalam DB, akan jauh lebih mudah untuk menulis front-end kedua atau lapisan-menengah nanti, karena Anda tidak harus mengimplementasikan kembali semuanya. Namun dalam praktiknya, saya pikir "di mana saya bisa melakukan ini dengan kode yang orang akan pahami" adalah faktor yang paling penting.

Kajetan Abt
sumber
Jika Anda mengubah dari jboss ke ruby, sangat mungkin Anda akan mengubah db (dan Anda tetap harus mengadopsi perhitungan ini) dan bukan tidak mungkin Anda dapat mengubah ke sesuatu yang lebih berbeda, seperti nosql.
Dainius
0

Untuk menyederhanakan cara menjawab ini adalah dengan melihat load balancing. Anda ingin meletakkan beban di tempat yang memiliki kapasitas paling besar (jika masuk akal). Dalam kebanyakan sistem itu adalah server SQL yang dengan cepat menjadi hambatan sehingga jawaban yang mungkin adalah bahwa Anda tidak ingin SQL melakukan satu ons pekerjaan lebih dari yang seharusnya.

Juga di sebagian besar arsitektur itu adalah SQL server (s) yang membentuk inti dari sistem dan sistem luar yang bisa ditambahkan.

Tetapi matematika di atas sangat sepele sehingga kecuali Anda mendorong sistem Anda ke batas tempat terbaik untuk meletakkannya adalah di mana Anda ingin meletakkannya. Jika matematika tidak sepele seperti menghitung sin / cos / tan untuk mengatakan perhitungan jarak maka upaya mungkin menjadi non-sepele dan memerlukan perencanaan dan pengujian yang cermat.

Donovanr
sumber
0

Jawaban lain untuk pertanyaan ini menarik. Anehnya, tidak ada yang menjawab pertanyaan Anda. Anda bertanya-tanya:

  1. Apakah lebih baik dilemparkan ke Sen dalam kueri? Saya tidak berpikir pemeran untuk sen menambahkan apa pun dalam kueri Anda.
  2. Apakah lebih baik digunakan sekarang () dalam kueri? Saya lebih suka memasukkan tanggal ke dalam kueri daripada menghitungnya dalam kueri.

Info lebih lanjut: Untuk pertanyaan pertama, Anda ingin memastikan bahwa menggabungkan pecahan bekerja tanpa kesalahan pembulatan. Saya pikir angka 19,2 masuk akal untuk uang dan dalam kasus kedua bilangan bulat itu OK. Menggunakan pelampung untuk uang salah karena alasan ini.

Untuk pertanyaan kedua, saya ingin memiliki kontrol penuh sebagai programmer tanggal berapa yang dianggap "sekarang". Sulit untuk menulis tes unit otomatis saat menggunakan fungsi seperti sekarang (). Juga, ketika Anda memiliki skrip transaksi yang lebih panjang, ada baiknya untuk menetapkan variabel sama dengan sekarang () dan menggunakan variabel sehingga semua logika menggunakan nilai yang sama persis.

Chris Schoon
sumber
0

Biarkan saya mengambil contoh nyata untuk menjawab pertanyaan ini

Saya perlu menghitung rata-rata bergerak tertimbang pada data ohlc saya, saya memiliki sekitar 134.000 lilin dengan simbol untuk masing-masing melakukannya

  1. Opsi 1 Lakukan dengan Python / Node dll
  2. Opsi 2 Lakukan dalam SQL itu sendiri!

Mana yang lebih baik?

  • Jika saya harus melakukan ini dengan Python, pada dasarnya, saya harus mengambil semua catatan yang disimpan di terburuk, kasus, melakukan perhitungan dan menyimpan semuanya kembali yang menurut saya merupakan pemborosan besar IO
  • Perubahan rata-rata bergerak tertimbang setiap kali Anda mendapatkan lilin baru yang berarti saya akan melakukan sejumlah besar IO secara berkala yang bukan pendapat yang baik dalam pertanda saya.
  • Dalam SQL, yang harus saya lakukan mungkin adalah menulis pemicu yang menghitung dan menyimpan semuanya jadi hanya perlu mengambil nilai WMA akhir untuk setiap pasangan setiap sekarang dan kemudian dan itu jauh lebih efisien

Persyaratan

  • Jika saya harus menghitung WMA untuk setiap lilin dan menyimpannya, saya akan melakukannya dengan Python
  • Tetapi karena saya hanya membutuhkan nilai terakhir, SQL jauh lebih cepat daripada Python

Untuk memberi Anda dorongan, ini adalah versi Python untuk melakukan moving average tertimbang

WMA dilakukan melalui kode

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 Melalui 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()

Percaya atau tidak, kueri berjalan lebih cepat daripada versi Pure Python dalam melakukan RATA-RATA BERGERAK BERAT !!! Saya selangkah demi selangkah menulis pertanyaan itu, jadi tunggu sebentar dan Anda akan baik-baik saja

Mempercepat

0,42141127300055814 detik Python

0,23801879299935536 detik SQL

Saya memiliki 134.000 catatan OHLC palsu di basis data saya dibagi di antara 1.000 saham sehingga itu adalah contoh di mana SQL dapat mengungguli server aplikasi Anda

PirateApp
sumber
1
Namun, Jika Anda perlu melakukan ini jutaan kali secepat mungkin, jauh lebih mudah untuk menelurkan aplikasi python paralel daripada replika db. Sampai skala tertentu bersandar lebih pada SQL tentu lebih cepat / lebih murah, tetapi akhirnya ada titik kritis ketika lebih baik untuk melakukan perhitungan ini dalam aplikasi Anda.
Lenny