2011-02-03 1 views
4

PostgreSQL의 다중 열 btree 색인을 활용하여 두 테이블 간의 성가신 조인을 수행하려고합니다.비교 ("<" and ">") 연산자를 사용하는 PostgreSQL 다중 열 색인 결합

   Table "revision_main" 
    Column  |   Type   | Modifiers 
----------------+------------------------+----------- 
revision_id | integer    | 
page_id  | integer    | 

Indexes: 
    "revision_main_pkey" UNIQUE, btree (revision_id) 
    "revision_main_cluster_idx" btree (page_id, "timestamp") CLUSTER 

이 표에는 위키의 페이지에 대한 수정본 (~ 300 백만 행)이 포함되어 있습니다. 내 테이블에는 더 많은 열이 있지만, 중요하지 않아야하므로이 예제에서는 제외했습니다.

   Table "revert" 
     Column  | Type | Modifiers 
--------------------+---------+----------- 
page_id   | integer | 
revision_id  | integer | 
reverted_to  | integer | 
Indexes: 
    "revert_page_between_idx" btree (page_id, reverted_to, revision_id) CLUSTER 

이 표에는 되돌리기 버전 (2200 만 줄)이 포함되어 있습니다. 리비전이 되돌려 진 경우 revision_id는 revision_main 테이블에 행을 가지며 revision_id와 revision_id 사이에 revision_id가 있으며 동일한 page_id를 공유합니다. 호기심이 있다면 http://en.wikipedia.org/wiki/Wikipedia:Revert을 참조하십시오.

복귀 된 개정판을 얻기 위해이 두 테이블에 합류하는 것은 간단합니다.

explain SELECT 
    r.revision_id, 
    rvt.revision_id 
FROM revision_main r 
INNER JOIN revert rvt 
    ON r.page_id = rvt.page_id 
    AND r.revision_id > rvt.reverted_to 
    AND r.revision_id < rvt.revision_id; 
             QUERY PLAN            
---------------------------------------------------------------------------------------------------- 
Merge Join (cost=4202878.87..15927491478.57 rows=88418194298 width=8) 
    Merge Cond: (r.page_id = rvt.page_id) 
    Join Filter: ((r.revision_id > rvt.reverted_to) AND (r.revision_id < rvt.revision_id)) 
    -> Index Scan using revision_main_page_id_idx on revision_main r (cost=0.00..9740790.61 rows=223163392 width=8) 
    -> Materialize (cost=4201592.06..4536465.21 rows=26789852 width=12) 
     -> Sort (cost=4201592.06..4268566.69 rows=26789852 width=12) 
       Sort Key: rvt.page_id 
       -> Seq Scan on revert rvt (cost=0.00..438534.52 rows=26789852 width=12) 

(">"때문에 "<"와 같은 비교 연산자를 지원)를 BTREE 인덱스해야 되돌리기에 클러스터 된 인덱스, 쿼리 최적화하지 않더라도 : 여기로 왔어요 것입니다 참여에 대한 색인을 사용하고 "explain"은 총 비용이 150 억이 넘을 것으로 예측합니다 (내년에 완료 될 수 있음).

비교 연산자는 다중 열 (btree) 인덱스와 함께 사용할 수 없습니까? 내가 잘못하고있는거야?

답변

5

옵티마이 저는 자신의 업무를 잘 알고있는 것처럼 보입니다.

테이블의 일부분 (하드웨어에 따라 다르지만 5 %라고 가정)을 선택하면 인덱스를 사용하는 것보다 전체 테이블을 선택하고 순서를 지정하는 것이 빠릅니다. 몇 행만 선택했다면 색인을 사용해야합니다. 따라서 데이터에 대한 올바른 쿼리 계획을 제공합니다.

총 비용은 해당 숫자가 모두 BS이며 하나의 쿼리 내에서 서로 비교할 때만 유용합니다. (매우 유사한 두 개의 쿼리가 생성하는 총 비용은 매우 다른 규모 일 수 있습니다.) 실행 시간과 쿼리 비용은 거의 무관합니다.

+0

난 그냥 인덱스를 사용하는 것보다 더 빠르게 할 수있는 전체 테이블을 정렬하는 방법을 볼 수 있습니다 ,하지만 내 경험에 의하면 비용 견적은 실행 시간을 일관되게 반영하는 경향이 있습니다. 반면에, 나는 그 숫자가 무엇을 의미하는지 결코 알지 못했습니다. 그래서 당신의 이해를 인정할 것입니다. 당신은 단지 쿼리를 실행하고 숫자를 무시해야한다고 제안하고 있습니까? – halfak

+0

@halfak : 자세히 살펴 보겠습니다. 데이터베이스는 작은 테이블로 조인을 시작하는 것과 같습니다. revision_main에 (page_id, revision_id)에 인덱스를 추가하면보다 효율적인 쿼리를 얻을 수 있습니다. 그것은 또한 더 나쁠 수도 있습니다. 그러나 이것이 실패 할 경우, 훨씬 더 효율적이되도록하는 유일한 방법은 더 적은 데이터를 요구하는 방법을 찾는 것입니다. – btilly

0

전체 Revert 테이블을 읽고 Revert 테이블의 각 행에 대해 적절한 수정 행을 찾는 것과 같은 쿼리 (SQL 기반)가있는 것 같습니다.

전체 되돌리기 테이블을 읽을 필요가 있으므로이를 순차적으로 검사하는 것이 적절합니다. 대략 행 수가 적을 것으로 예상됩니다.

각 되돌리기 행은 인덱스 스캔 및 병합 조인을 통해 가장 잘 수행 될 것으로 생각되는 여러 수정 버전과 일치하게됩니다. 평균적으로 각 되돌리기 행은 대략 3300 개의 개정과 일치하여 880 억 개의 행이됩니다.

880 억 개의 행을 신속하게 선택하는 방법을 모르겠습니다.

더 정확한 견적을 얻으려면 PostgreSQL에 각 되돌리기가 적용되는 개정 수가 3300 개 미만임을 확신하는 방법이 필요합니다.

여러 버전에 포함 된 경우에도 각 버전을 한 번만 표시해야한다는 것을 의미하는 되돌리기 버전이라고합니다.

그래서 비록 당신에게 되돌리기 개정을주지 않을 것 INNER JOIN

이 대신 EXISTS (subquery)를 사용해보십시오 :

EXPLAIN 
SELECT 
    r.revision_id 
FROM revision_main r 
WHERE EXISTS (SELECT 1 FROM revert rvt 
    WHERE r.page_id = rvt.page_id 
    AND r.revision_id > rvt.reverted_to 
    AND r.revision_id < rvt.revision_id); 
+0

"각 되돌리기 행은 대략 3300 개정과 일치하여 880 억 행이됩니다." --- 알겠습니다 ... 실제로 각 되돌리기는 되돌리기 행의 99 %에 대해 1 개정과 일치해야합니다. 이 사실을 분명히 할 수있는 방법이 있을까요? – halfak

+0

되돌리기가 발생할 때 되돌리기 페이지의 개정을 찾고 저장할 수 있습니다. –

관련 문제