2017-09-08 9 views
0

1 천만 개가 넘는 레코드가 포함 된 큰 테이블이 있으며 계속 커질 것입니다. 지난 24 시간의 레코드에 대한 집계 쿼리 (특정 값의 개수)를 수행하고 있습니다. 이 쿼리에 걸리는 시간은 테이블의 레코드 수에 따라 계속 증가합니다.쿼리 성능을 위해 별도로 레코드의 하위 집합을 보관하십시오. mysql

이 24 시간 레코드를 별도의 테이블에 보관하고 해당 테이블에서 집계를 수행하는 데 걸리는 시간을 제한 할 수 있습니다. mysql은 이러한 종류의 시나리오를 처리하는 기능을 제공합니까?

표 스키마 및 쿼리 참조 :

CREATE TABLE purchases (
    Id int(11) NOT NULL AUTO_INCREMENT, 
    ProductId int(11) NOT NULL, 
    CustomerId int(11) NOT NULL, 
    PurchaseDateTime datetime(3) NOT NULL, 
    PRIMARY KEY (Id), 
    KEY ix_purchases_PurchaseDateTime (PurchaseDateTime) USING BTREE, 
    KEY ix_purchases_ProductId (ProductId) USING BTREE, 
    KEY ix_purchases_CustomerId (CustomerId) USING BTREE 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

select COALESCE(sum(ProductId = v_ProductId), 0), 
     COALESCE(sum(CustomerId = v_CustomerId), 0) 
    into v_ProductCount, v_CustomerCount 
    from purchases 
    where PurchaseDateTime > NOW() - INTERVAL 1 DAY 
     and ( ProductId = v_ProductId 
      or CustomerId = v_CustomerId); 
+0

답변을 받았지만 질문을 다시 읽은 후 일부 형식의 파티션이 엄격한 테이블 기반 솔루션을 제공 할 수 있습니다. 내 머리 꼭대기에서 성능 상 영향이 있을지 모르겠으므로 어떤 대안에 대해서도 벤치마킹이 필요합니다. 자세한 안내는이 답변을 참조하십시오. https://stackoverflow.com/questions/12200359/how-to-partition-mysql-table-by-day –

답변

1

빌드와 별도의 Summary table을 유지한다.

파티셔닝을 사용하면 약간의 개선이 이루어 지거나 개선되지 않을 수도 있습니다. 요약표를 사용하면 10 배의 개선 효과를 얻을 수 있습니다.

요약 표에는 1 일 해상도가 있거나 1 시간이 필요할 수 있습니다. 현재 가지고있는 것에 SHOW CREATE TABLE을 입력하십시오. 더 자세한 내용을 논의 할 수 있습니다.

은 (당신이 원하는에 대한 기본 메커니즘이 없습니다.)

+0

또한 해당 위치에있는 INDEXing에 따라 매우 다릅니다. 적절한 인덱스가 많이 –

+0

이 테이블 스키마입니다 다음과 같은 일을 속도가 빨라집니다 : 는'표 구입 ( 아이디 INT (11) NOT NULL AUTO_INCREMENT, 제품 ID INT (11) NULL NOT을 생성, 고객 ID의 INT (11) NULL NOT, PurchaseDateTime 날짜 시간 (3) NULL NOT, PRIMARY KEY (ID) KEY ix_purchases_PurchaseDateTime USING BTREE, KEY ix_purchases_CustomerId (고객 ID)를 사용 BTREE, KEY ix_purchases_ProductId (제품 ID)를 사용하여 (PurchaseDateTime) BTREE ) ENGINE = 이노 DEFAULT CHARSET = 라틴 ;'지난 24 시간 동안 요약 테이블을 만들려면 어떻게해야합니까? – ctor

+0

현재 집계에 사용중인'SELECT'을 보여주십시오. –

0

A 계획

쿼리의 나머지 부분은 간단하게 처리하기 때문에 내가

 and ( ProductId = v_ProductId 
      or CustomerId = v_CustomerId) 

을 떠날 것이다 어쨌든 그것과 함께. 즉, 전체 SELECT는 INDEX의 BTREE 수행 할 수 있습니다 -

그럼 난 "포함하는"것

INDEX(PurchaseDateTime, ProductId, CustomerId) 

을 추가합니다. 모두에 필요한 데이터가 인덱스에 연속적으로 저장된다는 의미에서 '클러스터링'될 수도 있습니다. 예, 날짜 시간이 고의적으로 처음입니다. (OR 최적화하는 귀찮은이다. 나는 "인덱스 병합 조합"을 수행 할 최적화를 신뢰하지 않습니다.)

플랜 B

당신이 (때문에 v_ProductIdv_CustomerId의 거의 행을 터치 예상되는 경우 예), 다음과 같은 더 복잡한이면서, 빠를 수있다 : 모두 함께

SELECT COALESCE(sum(ProductId = v_ProductId), 0) 
    INTO v_ProductCount 
    FROM purchases 
    WHERE PurchaseDateTime > NOW() - INTERVAL 1 DAY 
     AND ProductId = v_ProductId; 
SELECT COALESCE(sum(CustomerId = v_CustomerId), 0) 
    INTO v_CustomerCount 
    FROM purchases 
    WHERE PurchaseDateTime > NOW() - INTERVAL 1 DAY 
     AND CustomerId = v_CustomerId; 

:

INDEX(ProductId, PurchaseDateTime), 
INDEX(CustomerId, PurchaseDateTime) 

예, 열의 순서는 의도적으로 다릅니다.

이러한 접근 방식 모두

원래 질문은 별도의 테이블의 원래 제안보다는 더 낫다. 이것들은 인덱스의 한 부분 (또는 두 개의 인덱스)에서 데이터를 분리함으로써 "분리"효과를냅니다. 그리고 이것들은 당신의 노력을 덜하면서 작업을 수행합니다.

+0

그러나 인덱스 조회 시간이 길어지기 때문에 테이블이 커질수록 이러한 쿼리의 실행 시간은 계속 증가 할 것입니다. 따라서 원본 테이블이 커지는 동안이 테이블의 인덱스 조회 시간이 일정하게 유지되도록 지난 24 시간 (또는 2 일) 레코드를 분리하는 것이 더 좋지 않습니까? – ctor

+0

백만 행 테이블의 포인트 쿼리는 X 밀리 초가 걸립니다. 1 조 행의 테이블에서 2X 밀리 초 밖에 걸리지 않습니다. 즉, 경기 침체가 매우 미미합니다. 내가 제안한 색인 및 재구성을 시도해 보셨습니까? 당신이 염려하는 유일한 '선택'입니까? –