通過組合(兩列)主鍵連接兩個表時,在查詢計劃中收到糟糕的基數估計。例如:具有複合主鍵的表的錯誤基數
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行。這在簡單查詢中不是問題,但是在執行復雜查詢時會導致非常慢的查詢計劃。我該如何幫助查詢優化器做得更好?
的問題是,主鍵和外鍵是過分指定的:對於兩個表x2完全依賴於x1的功能。這迷惑了優化者;它無法知道暗含的依賴性。只加入'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
@joop db可以知道連接不會放棄任何行,因爲外鍵用於連接。 –
我意識到這一點。但可能是優化器假定每個關鍵元素都將熵添加到密鑰空間(可能是啓發式選擇的錯誤選擇)。順便說一句:添加一個主鍵到t2沒有幫助。我的div/mod技巧確實改變了預期的行數。 – joop