Postgresql

修剪未使用的連接

  • October 10, 2017

我曾預計從視圖中選擇不會加入我不查詢任何值的表,但似乎並非如此。

我有一堆具有以下結構的表:

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。所有表中可能yearid值的集合都是相同的,並且在額外的表中給出:

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版本將避免在查詢視圖或內聯視圖時進行不必要的連接,如果有約束來強制執行省略連接對查詢沒有影響的邏輯,但我不確定他們是否會處理這種情況.

您幾乎可以肯定仍然會在執行計劃中看到潛在的聯接,因此這並不是判斷聯接中是否已花費任何工作的真正方法。

引用自:https://dba.stackexchange.com/questions/44331