Uygulamanızda sql'de hesaplamalar yapmanın artıları ve eksileri nelerdir?


154

shopkeeper tablo aşağıdaki alanları içerir:

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

Diyelim ki yukarıdaki tabloya sahibim. Dün için kayıtları almak ve miktarı sentlere yazdırarak bir rapor oluşturmak istiyorum.

Bunu yapmanın bir yolu java uygulamamda hesaplamalar yapmak ve basit bir sorgu yürütmektir

Date previousDate ;// $1 calculate in application

Date todayDate;// $2 calculate in application

select amount where createddate between $1 and $2 

ve daha sonra kayıtlar arasında döngü ve java uygulamamda sent sent dönüştürmek ve rapor oluşturmak

Başka bir yol, sql sorgusunun kendisinde hesaplamalar yapmak gibidir:

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

ve sonra kayıtlar arasında dolaşıp raporu oluşturur

Bir şekilde, tüm işlemlerim java uygulamasında yapılır ve basit bir sorgu açılır. Diğer durumda tüm dönüşümler ve hesaplamalar Sql sorgusunda yapılır.

Yukarıdaki kullanım durumu sadece bir örnektir, gerçek bir senaryoda bir tablo benzer türde işlem gerektiren birçok sütun içerebilir.

Performans ve diğer açılardan hangi yaklaşımın daha iyi olduğunu ve neden olduğunu söyleyebilir misiniz?


2
Tarih hesaplamalarının çok az etkisi olacaktır veya hiç etkisi olmayacaktır - sql motorunuzun gerçekten de tarihlerinizi yalnızca bir kez hesaplayacağı varsayılarak. Bunları uygulamanızda tanımlamak mükemmel bir mantıklıdır, çünkü rapor başlığı veya başka şeyler için bir şekilde orada tanımlanacaklardır. bu durumda değeri 100 ile çarpmak herhangi bir katmanda yapılabilir, çünkü bu satırlar arasında oluşturma için yine de döngü yapacaksınız ve * 100'ün ön uç dışındaki herhangi bir katmanda daha yavaş olması muhtemel değildir. Her iki durumda da hesaplamalarınız minimaldir ve performansla ilgili bir endişe değil, çevredeki operasyonlar tarafından gölgelenir.
Morg.

Yanıtlar:


206

Bu birçok faktöre bağlıdır - ama en önemlisi:

  • hesaplamaların karmaşıklığı (yani ölçeklerde beri, bir uygulama sunucusu üzerinde karmaşık çatırdayan yaparken tercih dışarı ; doğrusu ölçekler bir db sunucu daha yukarı )
  • veri hacmi (çok fazla veriye erişmeniz / toplamanız gerekiyorsa, db sunucusunda bunu yapmak bant genişliğini ve toplamlar dizinler içinde yapılabiliyorsa disk io'yu kaydedecektir)
  • kolaylık (sql karmaşık işler için en iyi dil değildir - özellikle prosedürel işler için mükemmel değildir, ancak set tabanlı işler için çok iyidir; yine de berbat hata işleme)

Eğer varsa, her zaman olduğu gibi, do sütunlar ve satırlar app-sunucuya veri geri getirmek minimize sizin yararınıza olacaktır. Sorgunun ayarlandığından ve uygun şekilde dizine eklendiğinden emin olmak her iki senaryoya da yardımcı olacaktır.

Notunuz:

ve sonra kayıtlar arasında dolaş

Kayıtlarda döngü yapmak neredeyse her zaman sql'de yapmak için yanlış bir şeydir - set tabanlı bir işlem yazmak tercih edilir.

Genel bir kural olarak , veritabanının işini en az "bu verileri sakla, bu verileri getir" şeklinde tutmayı tercih ederim - ancak sunucudaki zarif bir sorgunun çok fazla bant genişliği kaydedebileceği senaryo örnekleri her zaman vardır.

Ayrıca şunu da düşünün: eğer bu hesaplama pahalıysa, bir yerde önbelleklenebilir mi?

Doğru bir "daha iyi" istiyorsanız ; her iki şekilde kodlayın ve karşılaştırın (her ikisinin de ilk taslağının% 100 ayarlanmadığını belirterek). Ancak bunun tipik kullanımındaki faktör: eğer gerçekte, bir kerede 5 kez (ayrı ayrı) çağrılıyorsa, bunu simüle edin: sadece tek bir "bunlardan 1'i ve bunlardan 1'ini" karşılaştırmayın.


Döngü, daha fazla veya daha az "bir seferde satır" işlemeyi gerektirir. Bu da 2 * ağ gecikmesi artı dört bağlam anahtarı gidiş dönüş anlamına gelir. Evet: pahalı. "Yerel" DBMS işlemi, disk G / Ç'lerini (sistem çağrıları) en aza indirmek için tüm zor işleri yapar, ancak sistem çağrısı başına birden fazla satır almayı başarır. Bir seferde satır en az dört sistem çağrısı alır.
wildplasser

@wildplasser gerekli değildir; sunucu onlar geldikçe tükettiğiniz satır akış olabilir - bir "okuyucu" metafor nadir değildir.
Marc Gravell

1
@Marc Cavell: Buna bağlı. Bir uygulama programının kapladığı alanın yalnızca bir mantıksal kayıt olduğu durumda, az ya da çok Ok olur. Ama bildiğim "çerçevelerin" çoğu başlangıçta tüm kayıtları emmeye ve tek tek ateş etmeye eğilimlidir. Kilitleme başka bir tuzaktır.
wildplasser

İyi bir kural olduğunu düşünüyorum: SQL sunucu satırları nihayet gerek yok geri getirmeyin. Örneğin, toplu işlemler yapmanız gerekiyorsa, bunlar muhtemelen SQL'e aittir. Tablolar veya alt sorgular arasındaki birleşimler? SQL. Bu aynı zamanda rozetlerle kullandığımız yaklaşım ve şimdiye kadar ölçekle başa
çıkıyoruz

1
@zinking bu küme tabanlı bir işlem olurdu. Bu senaryoda döngü kodunu yazmazsınız - bu bir uygulama detayıdır. "Döngü" ile açık döngüler kastediyorum, örneğin bir imleç
Marc Gravell

86

Bir metafor kullanmama izin verin: Paris'te altın bir kolye satın almak istiyorsanız , kuyumcu Cape Town veya Paris'te oturabilirdi, bu bir beceri ve tat meselesi. Ama bunun için asla Güney Afrika'dan Fransa'ya tonlarca altın cevheri göndermezdin. Cevher madencilik sahasında (veya en azından genel alanda) işlenir, sadece altın gönderilir. Aynı şey uygulamalar ve veritabanları için de geçerli olmalıdır.

Bildiğim kadarıyla PostgreSQL konusu olduğunda, oldukça verimli bir sunucuda neredeyse her şeyi yapabilir. RDBMS karmaşık sorgularda mükemmeldir. Prosedürel ihtiyaçlar için çeşitli sunucu tarafı kod dilleri arasından seçim yapabilirsiniz : tcl, python, perl ve daha fazlası. Çoğunlukla PL / pgSQL kullanıyorum .

En kötü senaryo, daha büyük bir kümenin her satırı için tekrar tekrar sunucuya gitmek olacaktır. (Bu bir seferde bir ton cevher sevkiyatı gibi olurdu.)

İkincisi , her biri bir öncekine bağlı olarak bir sorgu dizisi gönderirseniz, hepsi sunucudaki bir sorguda veya yordamda yapılabilir. (Bu, altının ve mücevherlerin her birinin sırayla ayrı bir gemiyle gönderilmesi gibidir.)

Uygulama ve sunucu arasında gidip gelmek pahalıdır. Sunucu ve istemci için. Bunu azaltmaya çalışın ve kazanacaksınız: sunucu tarafı prosedürlerini ve / veya gerektiğinde karmaşık SQL'i kullanın.

Hemen hemen tüm karmaşık sorguları Postgres işlevlerine eklediğimiz bir projeyi bitirdik. Uygulama parametreleri teslim eder ve ihtiyaç duyduğu veri kümelerini alır. Hızlı, temiz, basit (uygulama geliştiricisi için), G / Ç minimuma indirildi ... düşük karbon ayak izine sahip parlak bir kolye.


12
Bu benzetmeyi, diğer geliştiricilerle anlamlı tasarım kararları vermek için kullanma konusunda dikkatli olurum. Analojiler, mantıklı olanlardan daha çok retorik bir cihazdır. Diğer faktörlerin yanı sıra, bir uygulama sunucusuna veri göndermek, altın cevherini kuyumculuğa göndermekten çok daha ucuzdur.
Doug

3
Cevheri altına dönüştürmek için teknolojiniz yoksa veya pahalıysa (madenciler bu diğer çalışanları öldürmek istediği için), daha ucuz olana bağlı olarak cevher veya altın gönderirsiniz, belki de başka bir yere gönderirsiniz. kuyumcu ve madenciler arasında, özellikle birden fazla kuyumcunuz varsa.
Dainius

1
tam olarak ne katılıyorum, SQL @a_horse_with_no_name döngü tabanlı hesaplama yapmak her zaman kötü bir şey olduğunu düşünmüyorum, bazen bu yine de yapılması gereken, daha ziyade veri Erwin'in metafor belirtildiği gibi getirildiğinde hesaplanır. veya veri geri getirildiğinde bunu bir maliyetle tekrarlamanız gerekir.
zinking

-1 Çünkü bu tek taraflı bir argüman, ödünleşmeleri yok sayar ve karşıt tarafın en iyi vakasını düşünmek ve reddetmek yerine karşı taraf için hasır bir adam kurar. "Uygulama ve sunucu arasında gidip gelmek pahalıdır" - kesinlikle: ama pahalı olan tek şey değildir ve çeşitli masraflar birbirine karşı tartılmalıdır. "Sofistike SQL" sorgularının veya saklı prosedürlerin belirli bir durum için en iyisi olduğu ortaya çıkabilir; ancak bu tür bir karar verilirken davanın ayrıntıları genellikle dikkate alınmalıdır.
yfeldblum

Serin analoji ama ne yazık ki yanlış varsayımlara dayanıyor. Nakliye altın cevheri çok yaygındır. Altın sıyırma oranı yaklaşık 1: 1'dir (altından atığa), ancak daha iyi ekipman ve işçilik kalitesinin olduğu yerlerde tesis dışında işlemek genellikle daha ucuzdur. Gönderinin büyüklüğüne bağlı olarak, işleme verimliliğini% 0,1 oranında artırmak gelirin göreli olarak artmasına neden olabilir (iki katına çıkan nakliye fiyatına rağmen) - altın bugünlerde oldukça pahalı olduğundan. Örneğin demir gibi diğer cevherler de tipik olarak sevk edilir (demirin sıyırma oranı yaklaşık% 60'tır!).
Chris Koston

18

Bu durumda sen muhtemelen veritabanı altyapısı Java daha verimli ondalık aritmetik planlarımızın olması muhtemeldir olarak biraz daha iyi SQL hesaplama yaparak kapalı.

Genellikle satır seviyesi hesaplamaları için fazla bir fark yoktur.

Bir fark yarattığı yer:

  • Burada SUM (), AVG (), MIN (), MAX () gibi toplu hesaplamalar, bir Java uygulamasından daha hızlı bir büyüklük sırası olacaktır.
  • Hesaplama, satırları filtrelemek için kullanılır. DB'de filtreleme, bir satırı okumak ve ardından atmaktan çok daha etkilidir.

12

SQL'de veri erişim mantığının hangi bölümlerinin ve uygulamanızda hangi bölümlerin gerçekleştirilmesi gerektiği konusunda siyah / beyaz yoktur. Mark Gravell'in ifadelerini seviyorum ,

  • karmaşık hesaplamalar
  • veri yoğun hesaplamalar

SQL'in gücü ve ifadesi büyük ölçüde hafife alınmıştır. Pencere fonksiyonlarının kullanılmasından bu yana, veritabanında çok sayıda kesin olarak ayarlanmamış hesaplama çok kolay ve zarif bir şekilde gerçekleştirilebilir.

Genel uygulama mimarisine bakılmaksızın her zaman üç temel kurala uyulmalıdır:

  • veritabanı ve uygulama arasında aktarılan veri miktarını ince tutmak (DB'deki şeyleri hesaplama lehine)
  • veritabanı tarafından diskten yüklenen veri miktarını ince tutmak (gereksiz veri erişimini önlemek için veritabanının ifadeleri optimize etmesine izin vermek)
  • veritabanını karmaşık, eşzamanlı hesaplamalar ile CPU sınırlarına zorlamayın (verileri uygulama belleğine çekmek ve orada hesaplamalar yapmak lehine)

Deneyimlerime göre, iyi bir DBA ve iyi veritabanınız hakkında bazı iyi bilgilerle, DBs CPU sınırlarınıza çok yakında girmeyeceksiniz.

Bunların açıklandığı yerlerden bazıları:


2

Genelde, aynı veya diğer projelerde başka modüllerin veya bileşenlerin de bu sonuçları alması gerekecekse SQL'de bir şeyler yapın. bir atomik işlem yapılan sunucu tarafı da daha iyidir, çünkü daha fazla işlem yapmadan son değerleri almak için herhangi bir db yönetim aracından depolanan proc'u çağırmanız yeterlidir.

Bazı durumlarda bu geçerli değildir, ancak geçerli olduğunda mantıklıdır. ayrıca genel olarak db kutusu en iyi donanım ve performanslara sahiptir.


Yeniden kullanılabilirlik herhangi bir aşamada mevcut olabilir ve SQL'de daha fazla hesaplama yapmak için bir neden (performans açısından) değildir. "Genel olarak db kutusu": bu yanlıştır ve ayrıca marc gravell'in dediği gibi, ölçekleme aynı şekilde çalışmaz. Çoğu veritabanının düzgün bir şekilde çalıştırılması için çok az donanım gerekir ve performans modelinin bir uygulama sunucusununkiyle çok az ilgisi vardır (yani tanrısal G / Ç üzerinde bir SQL sunucusu için bütçemin 2 / 3'ünü harcarken daha fazla harcama yapmam bir uygulama sahibinin depolama yığını için birkaç yüz kişiden fazla).
Morg.

1

ORM üzerine yazıyorsanız veya normal düşük performanslı uygulamalar yazıyorsanız, uygulamayı basitleştiren her türlü deseni kullanın. Yüksek performanslı bir uygulama yazıyorsanız ve ölçek hakkında dikkatlice düşünüyorsanız, işlemeyi verilere taşıyarak kazanacaksınız. İşlemeyi verilere taşımayı şiddetle savunuyorum.

Bunu iki adımda düşünelim: (1) OLTP (az sayıda kayıt) işlemleri. (2) OLAP (birçok kaydın uzun taramaları).

OLTP durumunda, hızlı olmak istiyorsanız (saniyede 10k - 100k işlem), mandal, kilit ve ölü kilit çekişmesini veritabanından kaldırmanız gerekir. Bu, işlemlerde uzun durakları ortadan kaldırmanız gerektiği anlamına gelir: işlemeyi istemciye taşımak için istemciden DB'ye gidiş-dönüşler böyle uzun bir duraktır. Uzun süreli işlemlere (atomik okuma / güncelleme yapmak için) sahip olamazsınız ve çok yüksek bir verim elde edemezsiniz.

Re: yatay ölçeklendirme. Modern veritabanları yatay olarak ölçeklenir. Bu sistemler HA ve hata toleransını zaten uygular. Bunu kullanın ve uygulama alanınızı basitleştirmeye çalışın.

OLAP'a bakalım - bu durumda muhtemelen terrabyte veriyi uygulamaya geri sürüklemenin korkunç bir fikir olduğu açık olmalıdır. Bu sistemler, sıkıştırılmış, önceden düzenlenmiş sütun verilere karşı son derece verimli çalışmak için özel olarak üretilmiştir. Modern OLAP sistemleri ayrıca yatay olarak ölçeklenir ve yatay olarak çalışmayı dağıtan karmaşık sorgu planlayıcılarına sahiptir (işleme dahili olarak veriye taşınır).


0

İş uygulamasında hedefimizi belirleyip belirleyemeyeceğimiz konusunda ön uçta veya arka uçta hesaplamalar yapıp yapmayacağına çok karar verilir. Java kodu, hem iyi yazılmış bir sql kodundan daha iyi performans gösterebilir, hem de tam tersi olabilir. Ama yine de şaşkınsanız önce belirlemeye çalışabilirsiniz -

  1. Eğer veritabanı sql üzerinden doğrudan bir şey elde edebilirsiniz, o zaman db çok daha iyi performans ve orada ve sonra sonuç getirme ile hesaplamalar yapmak gibi daha iyi gitmek. Ancak gerçek hesaplama burada ve orada çok fazla hesaplama gerektiriyorsa, uygulama koduyla gidebilirsiniz. Neden? Çünkü senaryo çoğu durumda döngü gibi en iyi sql tarafından ele alınmazken, ön uç diller bu şeyler için daha iyi tasarlanmıştır.
  2. Birçok yerden benzer hesaplama gerekiyorsa, o zaman açıkçası hesaplama kodunu db ucuna yerleştirmek, işleri aynı yerde tutmak daha iyi olacaktır.
  3. Birçok farklı sorgu yoluyla nihai sonuca ulaşmak için yapılacak çok fazla hesaplama varsa, aynı kodu arka uçtan sonuçları almak ve daha sonra bunları hesaplamaktan daha iyi performans için saklı bir yordama yerleştirebileceğiniz için db sonu için de gidin. son.

Kodu nereye yerleştireceğinize karar vermeden önce düşünebileceğiniz birçok başka yön vardır. Bir algı tamamen yanlış - Her şey Java'da en iyi yapılabilir (uygulama kodu) ve / veya her şey db (sql kodu) tarafından yapılacak en iyisidir.


0

Bir performans bakış açısı oluşturun: Bu, veritabanının temelini oluşturan disklerden verileri almaktan neredeyse çok daha hızlı gerçekleştirilebilen çok basit bir aritmetik işlemdir. Ayrıca, burada yan tümcesindeki değerlerin hesaplanması, herhangi bir çalışma zamanında çok hızlı olacaktır. Özetle, darboğaz, değerlerin hesaplanması değil, disk IO olmalıdır.

Okunabilirliğe göre, bir ORM kullanıyorsanız uygulama sunucusu ortamınızda yapmalısınız, çünkü ORM temel alınan verilerle set tabanlı işlemleri kullanarak çok kolay bir şekilde çalışmanıza izin verecektir. Zaten ham SQL yazacaksanız, oradaki hesaplamayı yapmakta yanlış bir şey yoktur, SQL'iniz de düzgün biçimlendirilmişse okunması biraz daha hoş ve daha kolay görünecektir.


0

Önemli bir şekilde, "performans" tanımlanmamıştır.

Benim için en önemli şey geliştirici zamanı.

SQL sorgusunu yazın. Çok yavaşsa veya DB bir darboğaz haline gelirse, yeniden düşünün. O zamana kadar, iki yaklaşımı kıyaslayabilir ve kararınızı kurulumunuzla ilgili gerçek verilere (donanım ve hangi yığında olursanız olun) dayalı olarak verebilirsiniz.


0

Performans farklılıklarının belirli örnekler ve ölçütler olmadan gerekçelendirilebileceğine inanmıyorum, ancak başka bir yaklaşımım var:

Hangisini daha iyi koruyabilirsiniz? Örneğin, kullanıcı arabiriminizi Java'dan Flash'a veya HTML5 veya C ++ veya başka bir şeye geçirmek isteyebilirsiniz. Çok sayıda program böyle bir değişikliğe uğradı, hatta başlamak için birden fazla dilde var, çünkü birden fazla cihazda çalışması gerekiyor.

Uygun bir orta katmanınız olsa bile (verilen örnekte durum böyle değil), bu katman değişebilir ve JBoss Ruby / Rails olabilir.

Öte yandan, SQL arka ucunu SQL ile ilişkisel DB olmayan bir şeyle değiştirmeniz olası değildir ve bunu yapsanız bile, ön ucu sıfırdan yeniden yazmanız gerekecektir, bu yüzden nokta tartışmalıdır.

Benim fikrim, DB'de hesaplamalar yaparsanız, daha sonra ikinci bir ön uç veya orta katman yazmak çok daha kolay olacaktır, çünkü her şeyi yeniden uygulamak zorunda değilsiniz. Ancak pratikte, "bunu insanların anlayacağı kodla nerede yapabilirim" en önemli faktör olduğunu düşünüyorum.


Eğer jboss'tan ruby'ye geçerseniz, muhtemelen db'yi değiştirirsiniz (ve yine de bu hesaplamaları benimsemeniz gerekir) ve nosql gibi daha farklı bir şeye geçmeniz pek olası değildir.
Dainius

0

Buna nasıl cevap verileceğini basitleştirmek için yük dengelemeye bakmak gerekir. Yükü en fazla kapasiteye sahip olduğunuz yere koymak istiyorsunuz (eğer mantıklıysa). Çoğu sistemde, hızlı bir şekilde bir darboğaz haline gelen SQL sunucusudur, bu yüzden muhtemelen cevap, SQL'in bir ons daha fazla iş yapmasını istememenizdir.

Ayrıca çoğu mimaride, sistemin çekirdeğini ve eklenen dış sistemleri oluşturan SQL sunucularıdır.

Ancak yukarıdaki matematik o kadar önemsiz ki, sisteminizi sınırlamak için zorlamadığınız sürece, onu koymak için en iyi yer koymak istediğiniz yerdir. Eğer matematik bir mesafe hesaplaması için sin / cos / tan hesaplamak gibi önemsiz değilse, çaba önemsiz olabilir ve dikkatli planlama ve test gerektirebilir.


0

Bu sorunun diğer cevapları ilginç. Şaşırtıcı bir şekilde, kimse sorunuzu cevaplamadı. Merak ediyorsun:

  1. Sorguda Cents'e yayın yapmak daha mı iyi? Kuruş sent için sorgunuza bir şey eklediğini sanmıyorum.
  2. Sorguda now () kullanmak daha mı iyi? Tarihleri ​​sorguda hesaplamak yerine sorguya geçirmeyi tercih ederim.

Daha fazla bilgi: Birinci soru için, kesirleri toplamanın yuvarlama hataları olmadan çalıştığından emin olmak istiyorsunuz. Bence sayı 19,2 para için makul ve ikinci durumda tamsayı tamam. Bu nedenle para için bir kayan nokta kullanmak yanlıştır.

İkinci soru için, bir programcı olarak hangi tarihin “şimdi” olarak değerlendirildiğini tam olarak kontrol etmek istiyorum. Şimdiki () gibi fonksiyonları kullanırken otomatik birim testleri yazmak zor olabilir. Ayrıca, daha uzun bir işlem komut dosyasına sahip olduğunuzda, şimdi () öğesine eşit bir değişken ayarlamak ve tüm mantığın tam olarak aynı değeri kullanması için değişkeni kullanmak iyi olabilir.


0

Bu soruyu ele almak için gerçek bir örnek vereyim

Ohlc verilerim üzerinde ağırlıklı bir hareketli ortalama hesaplamam gerekiyordu, her biri için bir sembol ile yaklaşık 134000 mumum var

  1. Seçenek 1 Python / Node vb.
  2. Seçenek 2 SQL'de yapın!

Hangisi daha iyi?

  • Bunu Python'da yapmak zorunda olsaydım, esasen, saklanan tüm kayıtları en kötü şekilde almalıyım, hesaplamayı yapmam ve bence büyük bir IO israfı olan her şeyi geri kurtarmam gerekirdi
  • Her yeni mum aldığınızda ağırlıklı hareketli ortalama değişiklikleri, düzenli aralıklarla büyük miktarlarda IO yapacağım anlamına geliyor, bu da benim işaretimde iyi bir fikir değil
  • SQL'de tek yapmam gereken, muhtemelen her şeyi hesaplayan ve saklayan bir tetikleyici yazmaktır, bu yüzden her bir çift için her seferinde nihai WMA değerlerini almanız yeterlidir ve bu çok daha verimlidir

Gereksinimler

  • Her mum için WMA'yı hesaplamam ve saklamam gerekirse Python'da yapardım
  • Ama sadece son değere ihtiyacım olduğundan, SQL Python'dan çok daha hızlı

Size biraz cesaret vermek için, bu ağırlıklı bir hareketli ortalama yapmak için Python sürümüdür

WMA kod yoluyla yapılır

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

SQL ile WMA

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

İster inanın ister inanmayın , sorgu AĞIRLIKLI HAREKETLİ ORTALAMA yapmanın Pure Python sürümünden daha hızlı çalışır !!!Bu sorguyu yazmaya adım adım gittim, orada durun ve iyi olacaksınız

hız

0.42141127300055814 saniye Python

0.23801879299935536 saniye SQL

Veritabanımda 1000 hisse arasında bölünmüş 134000 sahte OHLC kaydı var, böylece SQL uygulama sunucunuzdan daha iyi performans gösterebilir


1
Ancak, bunu mümkün olduğunca hızlı bir şekilde milyonlarca kez yapmanız gerekiyorsa, paralel python uygulamaları oluşturmak db kopyalarından çok daha kolaydır. SQL'e daha fazla eğilen belirli bir ölçek kesinlikle daha hızlı / daha ucuza kadar, ancak sonunda bu hesaplamayı uygulamanızda yapmanın daha iyi olduğu bir devrilme noktası vardır.
Lenny
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.