SQL과 응용 프로그램의 계산 수행의 장단점은 무엇입니까?


154

shopkeeper 표에는 다음과 같은 필드가 있습니다.

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

위의 테이블이 있다고 가정 해 봅시다. 어제 레코드를 가져 와서 센트로 인쇄하여 보고서를 생성하고 싶습니다.

한 가지 방법은 내 Java 응용 프로그램에서 계산을 수행하고 간단한 쿼리를 실행하는 것입니다.

Date previousDate ;// $1 calculate in application

Date todayDate;// $2 calculate in application

select amount where createddate between $1 and $2 

그런 다음 레코드를 반복하고 Java 응용 프로그램에서 금액을 센트로 변환하고 보고서를 생성합니다.

다른 방법은 SQL 쿼리 자체에서 계산을 수행하는 것과 같습니다.

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

그런 다음 레코드를 반복하고 보고서를 생성하십시오.

한 가지 방법으로, 모든 처리는 Java 응용 프로그램에서 수행되며 간단한 쿼리가 발생합니다. 다른 경우에는 모든 변환 및 계산이 SQL 쿼리에서 수행됩니다.

위의 사용 사례는 예일 뿐이며 실제 시나리오에서는 테이블에 유사한 종류의 처리가 필요한 많은 열이있을 수 있습니다.

성능 및 기타 측면에서 어떤 접근 방식이 더 나은지, 왜 그런지 말해 주시겠습니까?


2
날짜 계산은 전혀 영향을 미치지 않습니다 .SQL 엔진이 실제로 날짜를 한 번만 계산한다고 가정합니다. 어쨌든 보고서 제목이나 다른 것들에 대해 정의되기 때문에 응용 프로그램에서 정의하면 완벽하게 이해됩니다. 이 경우 값을 100으로 곱하면 모든 계층에서 수행 할 수 있습니다. 어쨌든 렌더링을 위해 해당 행을 반복하고 프런트 엔드를 제외한 모든 계층에서 * 100이 느려질 가능성이 없기 때문입니다. 두 경우 모두 성능 문제가 아닌 주변 작업으로 계산이 최소화되고 왜소합니다.
Morg.

답변:


206

그것은 많은 요인에 달려 있지만 가장 중요한 것은 다음과 같습니다.

  • 계산의 복잡성은 (그 규모 때문에, 응용 프로그램 서버에 복잡한 사각 사각을하고 선호 밖으로 오히려 확장되는 DB 서버보다 최대 )
  • 데이터 양 (많은 데이터에 액세스 / 집계해야하는 경우 db 서버에서 수행하면 대역폭이 절약되고 인덱스 내에서 집계를 수행 할 수있는 경우 디스크 io)
  • 편의성 (SQL은 복잡한 작업에 가장 적합한 언어는 아닙니다. 특히 절차 작업에는 적합하지 않지만 세트 기반 작업에는 적합합니다.

당신이 경우 언제나처럼, 열과 행을, 응용 프로그램 서버에 데이터를 다시 가져 최소화 당신의 이점에있을 것입니다. 쿼리를 조정하고 적절하게 색인을 작성하면 두 시나리오에 도움이됩니다.

다시 참고하십시오 :

그런 다음 레코드를 반복합니다.

레코드를 반복 하는 것은 거의 항상 SQL에서 잘못된 일입니다. 집합 기반 작업을 작성하는 것이 좋습니다.

일반적으로 데이터베이스 작업을 최소 "이 데이터 저장,이 데이터 가져 오기"로 유지하는 것이 좋습니다. 그러나 서버의 우아한 쿼리가 많은 대역폭을 절약 할 수있는 시나리오의 예는 항상 있습니다.

또한 계산 비용이 비싼 경우 어딘가에 캐시 할 수 있습니까?

정확한 "더 나은" 것을 원한다면 ; 두 가지 방법으로 코딩하고 비교하십시오 (둘 중 첫 번째 초안은 100 % 조정되지 않았을 것입니다). 그러나 일반적인 사용법을 고려하십시오. 실제로 실제로 한 번에 5 번 (별도로) 호출되는 경우 다음을 시뮬레이트합니다. 하나의 "1 대 1"만 비교하지 마십시오.


루핑은 "한 번에 한 줄에"처리하는 것을 의미합니다. 이는 2 * 네트워크 대기 시간과 4 개의 컨텍스트 스위치 왕복을 의미합니다. 예, 비싸요. "기본"DBMS 조작은 디스크 I / O (시스템 호출)를 최소화하기 위해 모든 노력을 기울이지 만 시스템 호출 당 둘 이상의 행을 페치하도록 관리합니다. 한 번에 행은 최소한 네 번의 시스템 호출을받습니다.
wildplasser

@wildplasser는 필요하지 않습니다; 서버는 행이 도착할 때 소비하는 행을 스트리밍 할 수 있습니다. "리더"은유는 드문 일이 아닙니다.
Marc Gravell

1
@Marc Cavell : 글쎄요. 어플리케이션 프로그램의 풋 프린트가 하나의 논리 레코드 인 경우에는 거의 비슷합니다. 그러나 내가 아는 대부분의 "frameworks"는 시작할 때 모든 레코드를 빨아 들여 하나씩 해고하는 경향이 있습니다. 잠금은 또 다른 함정입니다.
wildplasser

경험상 가장 좋은 방법은 다음과 같습니다. 궁극적으로 필요하지 않은 SQL Server 데이터 행을 다시 가져 오지 마십시오. 예를 들어 집계 작업을 수행해야하는 경우 SQL에 속할 수 있습니다. 테이블 또는 하위 쿼리 사이의 조인? SQL. 그것은 우리가 배지와 함께 사용하는 접근법이기도하며, 지금까지 우리는 scale :-)에 대처하고 있습니다.
Sklivvz

1
@zinking 그것은 집합 기반 작업이 될 것입니다. 이 시나리오에서는 루프 코드를 작성하지 않습니다. 이는 구현 세부 사항입니다. 예를 들어, 내가 명시 적 루프 의미는 "루핑"으로 커서
마크 Gravell

86

은유를 사용해 봅시다. 파리에서 황금 목걸이 를 사려면 금세 공인이 케이프 타운이나 파리에 앉아있을 수 있습니다. 그것은 기술과 맛의 문제입니다. 그러나 당신은 그것을 위해 남아프리카에서 프랑스로 금광을 절대로 보내지 않을 것 입니다. 광석은 채굴 현장 (또는 적어도 일반 지역)에서 처리되며 금만 배송됩니다. 앱과 데이터베이스도 마찬가지입니다.

지금까지로 PostgreSQL의이 우려, 당신은 아주 효율적으로, 서버에서 거의 모든 작업을 수행 할 수 있습니다. RDBMS는 복잡한 쿼리에 탁월합니다. 절차 상 필요에 따라 tcl, python, perl 등 다양한 서버 측 스크립트 언어 중에서 선택할 수 있습니다 . 대부분 PL / pgSQL을 사용 합니다.

최악의 시나리오는 더 큰 세트의 모든 단일 행마다 서버로 반복적으로 이동하는 것입니다. (한 번에 1 톤의 광석을 운송하는 것과 같습니다.)

두 번째 인라인 은 이전의 쿼리에 따라 일련의 쿼리를 보내면 모든 쿼리는 서버에서 하나의 쿼리 또는 절차로 수행 할 수 있습니다. (즉, 금과 각 보석을 별도의 선박으로 순차적으로 운송하는 것과 같습니다.)

앱과 서버 사이를 오가는 비용이 많이 듭니다. 서버 클라이언트 용. 이를 줄이려고하면 서버 측 프로 시저 및 / 또는 필요한 경우 정교한 SQL을 사용하는 것이 좋습니다.

우리는 거의 모든 복잡한 쿼리를 Postgres 함수로 압축 한 프로젝트를 마쳤습니다. 앱은 매개 변수를 넘겨 받아 필요한 데이터 세트를 얻습니다. 빠르고, 깨끗하고, 단순하며 (앱 개발자를 위해) I / O는 최소한으로 감소했습니다. 탄소 발자국이 적은 반짝이는 목걸이입니다.


12
이 비유를 사용하여 다른 개발자와 의미있게 디자인 결정을 내릴 때주의해야합니다. 유추는 논리적 장치보다 수사적 장치에 가깝습니다. 다른 요인들 중에서도 금광을 금세공에 배송하는 것보다 앱 서버에 데이터를 배송하는 것이 훨씬 저렴합니다.
Doug

3
더 싼 것에 따라 광석이나 금을 보내거나 광석을 금으로 변환하는 기술이 없거나 값이 비싸면 (광부가 다른 근로자를 죽이고 싶어하기 때문에) 다른 장소로 배송 할 것입니다. 특히 금세공이 하나 이상인 경우 금세공과 광부 사이.
Dainius

1
정확히 내가 동의하는 것은 SQL @a_horse_with_no_name에서 루프 기반 계산을하는 것이 항상 나쁜 것이라고 생각하지 않습니다. 어쨌든 이것이 수행되어야하지만 Erwin의 은유로 표시된 데이터를 가져올 때 계산됩니다. 또는 데이터를 다시 가져올 때 비용을 지불해야합니다.
zinking

-1 일방적 인 주장이기 때문에, 트레이드 오프를 무시하고 상대편의 최고의 사례를 고려하고 반박하는 대신 상대편에 밀짚을 설치합니다. "앱과 서버 간을 이동하는 것은 비용이 많이 듭니다"-절대 : 비싸지 않은 유일한 것은 아니며 다양한 비용을 서로 비교해야합니다. "정교한 SQL"쿼리 또는 저장 프로 시저가 특정 경우에 가장 적합 할 수 있습니다. 그러나 그러한 종류의 결정을 내릴 때 사건의 세부 사항을 일반적으로 고려해야합니다.
yfeldblum

근사한 비유이지만 불행히도 잘못된 가정에 기반합니다. 금 광석 배송은 매우 일반적입니다. 금 스트리핑 비율은 약 1 : 1 (금 대 폐기물)이지만 더 나은 장비와 솜씨의 품질을 이용할 수있는 외부에서 처리하는 것이 더 저렴합니다. 선적 규모에 따라 처리 효율이 0.1 % 증가하면 금이 상당히 비싸기 때문에 수입이 상대적으로 증가 할 수 있습니다 (배송 가격이 두 배가 되었음에도 불구하고). 예를 들어 철과 같은 다른 광석도 일반적으로 선적됩니다 (철의 스트리핑 비율은 약 60 %입니다!).
Chris Koston

18

이 경우는 아마 데이터베이스 엔진이 자바보다 더 효율적 소수점 연산 루틴을 가질 가능성이 높습니다로 약간 더 나은 SQL에서 계산을 끕니다.

일반적으로 행 수준 계산의 경우 큰 차이가 없습니다.

차이가 나는 곳은 다음과 같습니다.

  • SUM (), AVG (), MIN (), MAX ()와 같은 집계 계산은 데이터베이스 엔진이 Java 구현보다 훨씬 빠릅니다.
  • 어디서나 계산은 행을 필터링하는 데 사용됩니다. DB에서 필터링하는 것은 행을 읽은 다음 버리는 것보다 훨씬 효율적입니다.

12

SQL에서 수행해야 할 데이터 액세스 논리 부분과 응용 프로그램에서 수행해야 할 부분에 대해서는 흑백이 없습니다. 나는 Mark Gravell의 표현을 좋아합니다.

  • 복잡한 계산
  • 데이터 집약적 인 계산

SQL의 강력 함과 표현력은 과소 평가되었습니다. 윈도우 함수 가 도입 되었으므로 데이터베이스에서 엄격하지 않은 설정 지향 계산을 매우 쉽고 우아하게 수행 할 수 있습니다.

전반적인 애플리케이션 아키텍처에 관계없이 항상 세 가지 규칙을 따라야합니다.

  • 데이터베이스와 애플리케이션간에 전송되는 데이터의 양을 줄이십시오 (DB의 데이터 계산에 유리함)
  • 데이터베이스에 의해 디스크에서로드 된 데이터의 양을 줄입니다 (데이터베이스가 불필요한 데이터 액세스를 피하도록 명령문을 최적화하도록 유리함)
  • 복잡한 동시 계산을 통해 데이터베이스를 CPU 한도까지 푸시하지 마십시오 (데이터를 응용 프로그램 메모리로 가져 와서 계산 수행).

내 경험상, 적절한 DBA와 괜찮은 데이터베이스에 대한 약간의 지식이 있으면 곧 DB CPU 한계에 빠지지 않을 것입니다.

이 부분들을 설명하는 추가 자료 :


2

일반적으로 같은 프로젝트 또는 다른 프로젝트의 다른 모듈이나 구성 요소가 이러한 결과를 얻어야 할 가능성이있는 경우 SQL로 작업을 수행하십시오. 추가 작업없이 최종 값을 얻기 위해 모든 db 관리 도구에서 저장된 proc을 호출하면되기 때문에 서버 측에서 원자 적 작업이 더 좋습니다.

경우에 따라 적용되지 않지만 의미가있는 경우에는 적용됩니다. 또한 일반적으로 db 상자는 최상의 하드웨어 및 성능을 갖습니다.


재사용 성은 모든 계층에 존재할 수 있으며 SQL에서 더 많은 계산을 수행하는 이유는 아닙니다 (성능 현명). "일반적으로 db 상자": 이것은 잘못된 것이며, 더 나아가 marc gravell이 말했듯이 스케일링은 같은 방식으로 작동하지 않습니다. 대부분의 데이터베이스는 적절한 하드웨어 운영이 거의 필요하지 않으며 성능 패턴은 응용 프로그램 서버의 성능과 거의 관련이 없습니다. 앱 서버의 스토리지 스택의 경우 수백 개가 넘습니다).
Morg.

1

ORM을 기반으로 작성하거나 캐주얼 한 저 성능 응용 프로그램을 작성하는 경우 응용 프로그램을 단순화하는 패턴을 사용하십시오. 고성능 애플리케이션을 작성하고 스케일에 대해 신중하게 생각하는 경우 처리를 데이터로 이동하여 이길 수 있습니다. 처리를 데이터로 옮기는 것을 강력히 권합니다.

(1) OLTP (소수의 레코드) 트랜잭션 두 가지 단계로 이에 대해 생각해 봅시다. (2) OLAP (많은 레코드의 긴 스캔).

OLTP의 경우 속도를 높이려면 (초당 10k-100k 트랜잭션) 데이터베이스에서 래치, 잠금 및 교착 상태 경합을 제거해야합니다. 이것은 트랜잭션에서 긴 지연을 제거해야 함을 의미합니다. 클라이언트에서 DB 로의 왕복 이동은 클라이언트로 처리를 이동하는 것이 긴 지연 중 하나입니다. 읽기 / 업데이트 원자를 만들기 위해 오래 지속 된 트랜잭션을 가질 수 없으며 처리량이 매우 높습니다.

다시 : 수평 스케일링. 최신 데이터베이스는 수평 적으로 확장됩니다. 이러한 시스템은 이미 HA 및 내결함성을 구현합니다. 이를 활용하여 애플리케이션 공간을 단순화하십시오.

OLAP을 살펴 보자.이 경우 테라 바이트 단위의 데이터를 응용 프로그램으로 다시 끌어 오는 것이 끔찍한 아이디어라는 것이 분명해야합니다. 이 시스템은 압축 된 사전 구성된 컬럼 데이터에 대해 매우 효율적으로 작동하도록 특별히 설계되었습니다. 최신 OLAP 시스템은 또한 수평 적으로 확장되며 작업을 수평으로 분산시키는 정교한 쿼리 플래너 (내부로 처리를 데이터로 이동)를 가지고 있습니다.


0

프런트 엔드 또는 백엔드에서 계산을 수행할지 여부는 비즈니스 구현에서 목표를 결정할 수 있는지 여부에 따라 결정됩니다. 때때로 자바 코드는 잘 작성된 SQL 코드보다 성능이 좋을 수도 있고 그 반대 일 수도 있습니다. 그러나 여전히 혼란 스러우면 먼저 결정하려고 할 수 있습니다.

  1. 데이터베이스 sql을 통해 간단한 것을 얻을 수 있다면 db가 훨씬 더 잘 수행하고 계산을 수행 한 다음 결과 가져 오기로 더 잘 수행하십시오. 그러나 실제 계산에 여기에서 너무 많은 계산이 필요한 경우 응용 프로그램 코드를 사용할 수 있습니다. 왜? 대부분의 경우 시나리오는 루핑과 같이 프론트 엔드 언어가 이러한 것들을 위해 더 잘 설계된 SQL에서 가장 잘 처리되지 않기 때문입니다.
  2. 많은 장소에서 유사한 계산이 필요한 경우 계산 코드를 db 끝에 배치하는 것이 동일한 장소에 물건을 보관하는 것이 좋습니다.
  3. 많은 다른 쿼리를 통해 최종 결과를 얻기 위해 계산을 많이 해야하는 경우 백엔드에서 결과를 검색 한 다음 전면에서 계산하는 것보다 더 나은 수행을 위해 저장 프로 시저에 동일한 코드를 배치 할 수 있으므로 db end도 진행합니다 종료.

코드를 배치 할 위치를 결정하기 전에 생각할 수있는 다른 많은 측면이 있습니다. 한 가지 인식이 완전히 잘못되었습니다-모든 것이 Java (앱 코드)에서 가장 잘 수행 될 수 있으며 모든 것이 db (sql 코드)로 수행되는 것이 가장 좋습니다.


0

성능 관점을 형성하십시오 : 이것은 매우 간단한 산술 연산으로, 데이터베이스의 밑에있는 디스크에서 실제로 데이터를 가져 오는 것보다 훨씬 더 빠르게 수행 될 수 있습니다. 또한 where 절의 값을 계산하는 것은 모든 런타임에서 매우 빠를 수 있습니다. 요약하면 병목 현상은 값 계산이 아니라 디스크 IO 여야합니다.

가독성에 따라 ORM을 사용하면 응용 프로그램 서버 환경에서 ORM을 사용해야합니다. ORM을 사용하면 세트 기반 작업을 사용하여 기본 데이터로 매우 쉽게 작업 할 수 있기 때문입니다. 어쨌든 원시 SQL을 작성하려는 경우 계산을 수행하는 데 아무런 문제가 없으며 SQL이 올바르게 형식화되면 읽기가 더 좋고 읽기 쉽습니다.


0

결정적으로 "성능"은 정의되지 않습니다.

나에게 가장 중요한 것은 개발자 시간입니다.

SQL 쿼리를 작성하십시오. 너무 느리거나 DB에 병목 현상이 발생하면 다시 고려하십시오. 그때까지 두 가지 접근 방식을 벤치마킹하고 설정과 관련된 실제 데이터 (하드웨어 및 현재 사용중인 스택)를 기반으로 결정을 내릴 수 있습니다.


0

구체적인 예와 벤치 마크가 없으면 성능 차이를 추론 할 수 있다고 생각하지 않지만 다른 견해가 있습니다.

어느 쪽을 더 잘 유지할 수 있습니까? 예를 들어 프론트 엔드를 Java에서 Flash, HTML5, C ++ 또는 다른 것으로 전환하려고 할 수 있습니다. 다수의 프로그램이 그러한 변화를 겪었거나 여러 장치에서 작동해야하기 때문에 처음부터 여러 언어로 존재합니다.

적절한 예의 중간 계층이 있더라도 (주어진 예제에서는 그렇지 않은 것 같습니다) 해당 계층이 변경되고 JBoss가 Ruby / Rails가 될 수 있습니다.

반면, SQL 백엔드를 관계형 DB가 아닌 SQL로 바꿀 가능성은 거의 없으며, 그렇게해도 프론트 엔드를 처음부터 다시 작성해야하므로 요점은 무의미합니다.

내 생각은 DB에서 계산을 수행하면 나중에 모든 것을 다시 구현할 필요가 없기 때문에 나중에 두 번째 프런트 엔드 또는 중간 계층을 작성하는 것이 훨씬 쉽다는 것입니다. 그러나 실제로는 "사람들이 이해할 수있는 코드로 어디에서 할 수 있는가"가 가장 중요한 요소라고 생각합니다.


jboss에서 ruby로 변경하면 db를 변경할 가능성이 높습니다 (어쨌든이 계산을 채택해야 할 것입니다). nosql과 같이 더 다른 것으로 바꿀 수는 없습니다.
Dainius

0

이에 대한 답변을 단순화하려면로드 밸런싱을 살펴보십시오. 용량이 가장 큰 곳에로드를 배치하려고합니다 (의미가있는 경우). 대부분의 시스템에서 빠르게 병목 현상이 발생하는 것은 SQL 서버이므로 아마도 SQL이 필요 이상으로 1 온스 이상의 작업을 수행하지 않기를 원할 것입니다.

또한 대부분의 아키텍처에서 시스템의 핵심을 구성하는 SQL Server와 외부 시스템이 추가됩니다.

그러나 위의 수학은 매우 사소한 일이므로 시스템을 한계까지 밀어 넣지 않는 한 가장 좋은 장소는 원하는 곳입니다. 거리 계산을 위해 sin / cos / tan을 계산하는 것과 같이 수학이 사소한 것이 아니라면 노력이 쉽지 않을 수 있으며 신중한 계획과 테스트가 필요할 수 있습니다.


0

이 질문에 대한 다른 대답은 흥미 롭습니다. 놀랍게도 아무도 당신의 질문에 대답하지 않았습니다. 궁금합니다 :

  1. 쿼리에서 센트로 캐스팅하는 것이 더 낫습니까? 나는 센트로 캐스트하면 쿼리에 아무것도 추가하지 않는다고 생각합니다.
  2. 쿼리에서 now ()를 사용하는 것이 더 낫습니까? 쿼리에서 날짜를 계산하는 대신 날짜를 쿼리에 전달하는 것을 선호합니다.

추가 정보 : 문제 1의 경우 분수를 모으는 것이 반올림 오류없이 작동하는지 확인하고 싶습니다. 나는 숫자 19,2가 돈에 합리적이라고 생각하고 두 번째 경우에는 정수가 괜찮습니다. 이 이유로 돈에 플로트를 사용하는 것은 잘못입니다.

2 번 문제는 어떤 날짜가 "현재"로 간주되는지 프로그래머로서 모든 권한을 갖고 싶습니다. now ()와 같은 함수를 사용할 때 자동 단위 테스트를 작성하기가 어려울 수 있습니다. 또한 더 긴 트랜잭션 스크립트가있는 경우 변수를 now ()와 동일하게 설정하고 변수를 사용하여 모든 논리가 정확히 동일한 값을 사용하도록하는 것이 좋습니다.


0

이 질문을 해결하기 위해 실제 예를 들어 보겠습니다.

내 ohlc 데이터에 대한 가중 이동 평균을 계산해야했으며, 각각에 대한 기호가있는 약 134000 개의 양초가 있습니다.

  1. 옵션 1 Python / Node 등에서 수행
  2. 옵션 2 SQL 자체로 수행하십시오!

어느 것이 더 낫습니까?

  • 파이썬 에서이 작업을 수행해야한다면 본질적으로 최악의 경우 모든 저장된 레코드를 가져 와서 계산을 수행하고 모든 것을 다시 저장해야합니다. 내 의견으로는 IO의 막대한 낭비입니다.
  • 새로운 양초를 얻을 때마다 가중 이동 평균 변화는 정기적 인 간격으로 엄청난 양의 IO를 수행한다는 것을 의미합니다.
  • SQL에서해야 할 일은 아마도 모든 것을 계산하고 저장하는 트리거를 작성하는 것입니다. 따라서 각 쌍의 최종 WMA 값을 매번 가져와야하므로 훨씬 효율적입니다.

요구 사항

  • 모든 촛불에 대해 WMA를 계산하고 저장해야한다면 파이썬에서 할 것입니다.
  • 그러나 마지막 값만 필요하므로 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()

SQL을 통한 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()

믿거 나 말거나 , 쿼리는 WEIGHTED MOVING AVERAGE를 수행하는 순수 Python 버전보다 빠르게 실행됩니다 !!! 나는 그 쿼리를 작성하는 단계적으로 갔으므로 거기에 매달 아라. 그러면 잘 할 것이다.

속도

0.42141127300055814 초 파이썬

0.23801879299935536 초 SQL

내 데이터베이스에 134000 개의 가짜 OHLC 레코드가 1000 개 주식으로 나누어 져 있으므로 SQL이 앱 서버를 능가하는 예입니다.


1
그러나이 작업을 가능한 빨리 수백만 번 수행해야하는 경우 DB 복제본보다 병렬 파이썬 앱을 생성하는 것이 훨씬 쉽습니다. SQL에 더 많은 기대를 기울일 때까지 확실히 더 빠르거나 저렴할 수 있지만 결국에는 응용 프로그램에서이 계산을 수행하는 것이 더 좋은 팁이 있습니다.
Lenny
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.