2013-09-26 7 views
2

복합 키 (두 열) 기본 키를 통해 두 테이블을 조인 할 때 쿼리 계획에서 카디널리티가 잘못 계산됩니다. 예 :복합 기본 키가있는 테이블의 카디널리티가 올바르지 않음

CREATE TABLE t1 AS SELECT x, x*2 AS x2 FROM generate_series(0, 1000) AS x; 
ALTER TABLE t1 ADD PRIMARY KEY(x, x2); 
ANALYZE t1; 

CREATE TABLE t2 AS SELECT x, x*2 AS x2 FROM generate_series(0, 1000) AS x; 
ALTER TABLE t2 ADD FOREIGN KEY (x, x2) REFERENCES t1(x,x2); 
ANALYZE t2; 

EXPLAIN ANALYZE 
SELECT * 
FROM t1 JOIN t2 USING (x, x2) 

QUERY PLAN                          
------------------------------------------------------------------------------------------------------------- 
Hash Join (cost=30.02..52.55 rows=1 width=8) (actual time=0.660..1.551 rows=1001 loops=1)      
    Hash Cond: ((t1.x = t2.x) AND (t1.x2 = t2.x2))                
    -> Seq Scan on t1 (cost=0.00..15.01 rows=1001 width=8) (actual time=0.021..0.260 rows=1001 loops=1)  
    -> Hash (cost=15.01..15.01 rows=1001 width=8) (actual time=0.620..0.620 rows=1001 loops=1)     
     Buckets: 1024 Batches: 1 Memory Usage: 40kB               
     -> Seq Scan on t2 (cost=0.00..15.01 rows=1001 width=8) (actual time=0.019..0.230 rows=1001 loops=1) 
Total runtime: 1.679 ms  

계획에는 하나의 반환 된 행이 필요하지만 사실 1001 개의 행이 반환됩니다. 이것은 간단한 쿼리에서 문제가 아니지만 복잡한 쿼리를 수행 할 때 쿼리 계획이 매우 느리게됩니다. 쿼리 최적화 프로그램이 어떻게 도움이 될 수 있습니까?

+0

을 그 기본 키와 외래 키 두 테이블 모두에 대해 x2는 x1에 따라 완전히 기능합니다. 이것은 optimzer를 혼란스럽게합니다. 묵시적 의존성을 알 수 없다. 단지't1.x = t2.x'에 합류하면 올바른 추정치가 나온다. 또한 'CREATE TABLE t1 AS SELECT x/100 AS x, x % 100 AS x2 FROM generate_series (0, 10000) AS x;'(t2와 동일)는 정확한 추정치를 제공합니다. – joop

+0

@joop db는 외래 키가 조인에 사용되므로 조인이 모든 행을 버리지 않음을 알 수 있습니다. –

+0

나는 그것을 알고있다. 그러나 옵티마이 저는 각 핵심 요소가 키 공간에 엔트로피를 추가한다고 가정 할 수 있습니다 (아마도 잘못된 선택/발견 적 순서). BTW : t2에 기본 키를 추가해도 도움이되지 않습니다. 내 div/mod 트릭은 예상되는 행 수를 변경합니다. – joop

답변

1

하나의 열이 다른 열에 완전히 종속되어있는 복합 기본 키를 사용하는 것이 "흥미로운"디자인입니다.

어떤 경우 든 PostgreSQL은 현재 각 열의 선택도가 서로 독립적이라고 가정하므로 기본 색인 인 경우에도 동일한 인덱스에 있는지 여부에 관계없이 함께 곱합니다. 그 주위에 좋은 길을 알지 못합니다. 진정으로 직교 핵심 요소 만들

EXPLAIN ANALYZE 
SELECT * 
FROM t1 JOIN t2 on (t1.x=t2.x and t1.x2 between t2.x2 and t2.x2); 
+0

두 번째 열은 실제로 첫 번째 열에 종속되지 않습니다. 테스트 데이터를 만드는 더 좋은 방법을 생각할 수 없었습니다. 제안을 환영합니다! –

+0

좋은 트릭! 실제로 작동합니다. – joop

0

또 다른 방법 :

당신은 진정한 선택에 가까워 질이 핑계를 사용할 수있는 문제가

CREATE TABLE t1 AS SELECT x/100 AS x, x%100 AS x2 FROM generate_series(0, 10000) AS x; 
ALTER TABLE t1 ADD PRIMARY KEY(x, x2); 
ANALYZE t1; 

CREATE TABLE t2 AS SELECT x/100 AS x, x%100 AS x2 FROM generate_series(0, 10000) AS x; 
ALTER TABLE t2 ADD PRIMARY KEY (x, x2) ; -- added PK 
ALTER TABLE t2 ADD FOREIGN KEY (x, x2) REFERENCES t1(x,x2); 

ANALYZE t2; 
+0

감사합니다.이 방법은 테스트 데이터를 만드는 좋은 방법입니다. –