Postgresql
修剪未使用的連接
我曾預計從視圖中選擇不會加入我不查詢任何值的表,但似乎並非如此。
我有一堆具有以下結構的表:
CREATE TABLE ind1 (year integer, id integer, ind1 float); ALTER TABLE ind1 ADD PRIMARY KEY (year, id); INSERT INTO ind1 VALUES (2000, 1, 0.0); INSERT INTO ind1 VALUES (2000, 2, 0.3); INSERT INTO ind1 VALUES (2000, 3, 1.1); INSERT INTO ind1 VALUES (2001, 1, 0.0); INSERT INTO ind1 VALUES (2001, 2, 0.3); INSERT INTO ind1 VALUES (2001, 3, 1.1); INSERT INTO ind1 VALUES (2002, 1, 0.0); INSERT INTO ind1 VALUES (2002, 2, 0.3); INSERT INTO ind1 VALUES (2002, 3, 1.1); VACUUM ANALYZE ind1;
還有,,,
ind2
……ind3
。所有表中可能year
和id
值的集合都是相同的,並且在額外的表中給出:CREATE TABLE id (id integer PRIMARY KEY); INSERT INTO id VALUES (1); INSERT INTO id VALUES (2); INSERT INTO id VALUES (3); VACUUM ANALYZE id;
現在我創建一個視圖來顯示給定年份的所有條目:
CREATE VIEW ind_2000 AS SELECT id, ind1, ind2, ind3 FROM (SELECT id, 2000 AS year FROM id) T LEFT JOIN ind1 USING (year, id) LEFT JOIN ind2 USING (year, id) LEFT JOIN ind3 USING (year, id);
但是,當僅選擇列和
id
時,仍然連接所有表,儘管這不是正確執行查詢所必需的:ind1``ind2
EXPLAIN ANALYZE SELECT id, ind1, ind2 FROM ind_2000; QUERY PLAN ---------------------------------------------------------------------------------------------------------------------- Hash Left Join (cost=3.45..4.63 rows=3 width=20) (actual time=0.150..0.157 rows=3 loops=1) Hash Cond: (id.id = ind1.id) -> Hash Left Join (cost=2.30..3.43 rows=3 width=12) (actual time=0.118..0.124 rows=3 loops=1) Hash Cond: (id.id = ind2.id) -> Hash Left Join (cost=1.15..2.23 rows=3 width=4) (actual time=0.087..0.089 rows=3 loops=1) Hash Cond: (id.id = ind3.id) -> Seq Scan on id (cost=0.00..1.03 rows=3 width=4) (actual time=0.007..0.007 rows=3 loops=1) -> Hash (cost=1.11..1.11 rows=3 width=4) (actual time=0.028..0.028 rows=3 loops=1) -> Seq Scan on ind3 (cost=0.00..1.11 rows=3 width=4) (actual time=0.019..0.024 rows=3 loops=1) Filter: (2000 = year) -> Hash (cost=1.11..1.11 rows=3 width=12) (actual time=0.012..0.012 rows=3 loops=1) -> Seq Scan on ind2 (cost=0.00..1.11 rows=3 width=12) (actual time=0.007..0.011 rows=3 loops=1) Filter: (2000 = year) -> Hash (cost=1.11..1.11 rows=3 width=12) (actual time=0.011..0.011 rows=3 loops=1) -> Seq Scan on ind1 (cost=0.00..1.11 rows=3 width=12) (actual time=0.007..0.009 rows=3 loops=1) Filter: (2000 = year) Total runtime: 0.304 ms (17 rows)
整個程式碼都在這個 gist中。
我如何告訴優化器避免無用的連接?
(使用 PostgreSQL 8.4)
編輯:即使刪除時間維度,錯誤仍然存在,請參閱要點中的option1.sql。
外連接刪除在 PostgreSQL 9.0 中實現。我建議您使用該版本(或更新的版本)嘗試您的範例。
您只考慮 ind3 中可能有 0 個或 1 個連接行 - 如果有 7 個,那麼它將影響從查詢返回的行數,因此說連接無關緊要是不正確的。
即使不是這種情況,查詢優化器中是否實現了潛在的優化操作也是一個問題。最近的Oracle版本將避免在查詢視圖或內聯視圖時進行不必要的連接,如果有約束來強制執行省略連接對查詢沒有影響的邏輯,但我不確定他們是否會處理這種情況.
您幾乎可以肯定仍然會在執行計劃中看到潛在的聯接,因此這並不是判斷聯接中是否已花費任何工作的真正方法。