2009-11-05 70 views
3

我開始更好地掌握PostgreSQL索引,但是我遇到了OR條件的問題,在那裏我不知道該怎麼去優化我的索引以獲得更快的查詢。高級索引涉及OR-ed條件(pgsql)

我有6個條件,當單獨運行時,似乎有一個小的成本。以下是修剪查詢的示例,包括查詢計劃計算的時間。

注:我沒有輸出低於降低複雜起見,這些查詢的實際查詢計劃,但它們都使用nested loop left joinsindex scans,我會用正確的索引想到如果有必要,我可以包括查詢計劃爲一個更有意義的響應。

EXPLAIN ANALYZE SELECT t1.*, t2.*, t3.* 
    FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id 
WHERE (conditions1) 
LIMIT 10; 

QUERY PLAN 
------------------------------------------------------------------------------------- 
Limit (cost=0.25..46.69 rows=1 width=171) (actual time=0.031..0.031 rows=0 loops=1) 

EXPLAIN ANALYZE SELECT t1.*, t2.*, t3.* 
    FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id 
WHERE (conditions2) 
LIMIT 10; 

QUERY PLAN 
------------------------------------------------------------------------------------- 
Limit (cost=0.76..18.97 rows=1 width=171) (actual time=14.764..14.764 rows=0 loops=1) 

/* snip */ 

EXPLAIN ANALYZE SELECT t1.*, t2.*, t3.* 
    FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id 
WHERE (conditions6) 
LIMIT 10; 

QUERY PLAN 
------------------------------------------------------------------------------------- 
Limit (cost=0.51..24.48 rows=1 width=171) (actual time=0.252..5.332 rows=10 loops=1) 

我的問題是,我想與OR運算符一起參加這些6個條件,使每個條件的可能性。我的組合查詢出現更多這樣的:

EXPLAIN ANALYZE SELECT t1.*, t2.*, t3.* 
    FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id 
WHERE (conditions1 OR conditions2 OR conditions3 OR conditions4 OR conditions5 OR conditions 6) 
LIMIT 10; 

不幸的是,這會導致查詢計劃,這似乎不再使用我的指標大幅增加(相反,選擇做一個hash left join而非nested loop left join,並在之前使用的index scans上執行各種sequence scans)。

Limit (cost=142.62..510755.78 rows=1 width=171) (actual time=30.591..30.986 rows=10 loops=1) 

有沒有什麼特別的東西我應該知道關於OR-ed條件的索引以改進我的最終查詢?

UPDATE:如果我爲每個單獨的SELECT使用UNION,那似乎加快了查詢速度。但是,如果我選擇在未來,這會阻止我訂購我的結果嗎?這是我做了通過聯盟加快查詢:

EXPLAIN ANALYZE 
SELECT t1.*, t2.*, t3.* 
    FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id 
WHERE (conditions1) 
UNION 
SELECT t1.*, t2.*, t3.* 
    FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id 
WHERE (conditions2) 
UNION 
SELECT t1.*, t2.*, t3.* 
    FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id 
WHERE (conditions3) 
UNION 
SELECT t1.*, t2.*, t3.* 
    FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id 
WHERE (conditions4) 
UNION 
SELECT t1.*, t2.*, t3.* 
    FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id 
WHERE (conditions5) 
UNION 
SELECT t1.*, t2.*, t3.* 
    FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id 
WHERE (conditions6) 
LIMIT 10; 

QUERY PLAN 
------------------------------------------------------------------------------------- 
Limit (cost=219.14..219.49 rows=6 width=171) (actual time=125.579..125.653 rows=10 loops=1) 

回答

4

根據不同的條件,它可能是邏輯上是不可能使用任何指標,以幫助使用OR表情複雜的條件。

像MySQL和PostgreSQL 8.0和更早的國家在其docs on indexes

注意查詢或數據操作命令可以使用每個表最多一個索引。

使用PostgreSQL 8.1,這有changed

但是,如果這不起作用,您可以使用您嘗試的UNION解決方案(這是MySQL用戶的常見解決方案,該解決方案仍然具有每表一個索引的限制)。

您應該能夠訂購UNION查詢的結果,但你必須用括號來指定該ORDER BY適用於UNION的結果,而不是僅僅在鏈中的最後一個子查詢。

(SELECT ...) 
UNION 
(SELECT ...) 
UNION 
(SELECT ...) 
ORDER BY columnname; 

我希望這可以幫助;我不是PostgreSQL優化器的專家。您可以嘗試搜索mailing list archives,或者要求在IRC channel

+0

我相信8.1改變你所指出的仍是被查詢規劃確定的,因此如果沒有出現被使用,那麼我基本上不會能夠使用它我的或條件?它看起來像我將需要使用UNION的,但它的好,知道如何通過使用括號來限制結果。謝謝! – 2009-11-05 01:58:39

+0

另外,我沒有意識到,只有(之前8.1)的單個指數在查詢計劃中使用。這有助於我更好地理解我應該如何創建索引,所以謝謝您指出。 – 2009-11-05 02:02:27

2

(對不起 - 不知道如何回答的回覆,所以這是怎麼回事頂層)

爲了澄清 - PG用於只使用一個索引單個表掃描。如果你有一個連接三個表的查詢,並且每個表都有一個有用的索引,那麼使用這三個表總是足夠聰明。

在什麼是可能發生的事情你的具體情況是,你有你的邏輯或條件之間有着某種聯繫。 PostgreSQL不知道這一點,所以最終假設它會匹配比實際更多的行。足夠的行來改變你的查詢計劃。

而且因爲你限制每個小一個單獨而不是整個結果集使用UNION你被聯合查詢是不太一樣的單獨一個。

您應該能夠訂購 結果UNION查詢的,但你必須 使用括號來指定 ORDER BY應用於的的 結果結合,不僅最後 子查詢在鏈中。

這是不對的 - ORDER BY適用於整個結果。

HTH

+0

感謝您的額外幫助。我肯定知道更多關於PostgreSQL和索引的知識,而不是我在開啓這個問題之前所做的。 :) – 2009-11-06 16:48:15

+0

另外,回答你的問題,你需要獲得更多的銷售代表之前,你可以發表評論。只要回答這樣的人的問題,你就會獲得代表。我想你只需要15位代表發表意見,而不是一個很大的障礙。 – 2009-11-06 16:49:11