2014-10-22 64 views
0

指數:綜合指數。 - 違反最左邊的原則?

CREATE INDEX message_index ON message(queue_id, target_client_id, timestamp ASC, source_client_id); 

查詢:

EXPLAIN ANALYZE 
SELECT content 
    FROM message 
WHERE message.queue_id = 1 
    AND message.source_client_id = 1 
    AND (message.target_client_id = -1 OR message.target_client_id = 1); 

輸出:

Bitmap Heap Scan on message (cost=8.87..12.89 rows=1 width=13) (actual time=0.022..0.026 rows=50 loops=1) 
    Recheck Cond: (((queue_id = 1) AND (target_client_id = (-1)) AND (source_client_id = 1)) OR ((queue_id = 1) AND (target_client_id = 1) AND (source_client 
_id = 1))) 
    -> BitmapOr (cost=8.87..8.87 rows=1 width=0) (actual time=0.017..0.017 rows=0 loops=1) 
     -> Bitmap Index Scan on message_index (cost=0.00..4.43 rows=1 width=0) (actual time=0.011..0.011 rows=0 loops=1) 
       Index Cond: ((queue_id = 1) AND (target_client_id = (-1)) AND (source_client_id = 1)) 
     -> Bitmap Index Scan on message_index (cost=0.00..4.44 rows=1 width=0) (actual time=0.006..0.006 rows=50 loops=1) 
       Index Cond: ((queue_id = 1) AND (target_client_id = 1) AND (source_client_id = 1)) 

這又如何查詢使用與問候索引source_client_id即最右邊一列綜合指數沒有第三列(timestamp)正在參與查詢所有?

根據這裏的最後一個答案How important is the order of columns in indexes?這應該是無效的。我錯過了什麼?

+1

它有效地使用謂詞'timestamp ='anything''爲第3列。 BTW'timestamp'是表列的錯誤名稱。這是一個保留字,沒有商業意義。 – 2014-10-22 09:37:16

+0

我在過去24小時內發佈了三個問題。每個包含「timestamp」列,每次有人提到它。 SO很棒;)@a_horse_with_no_name如果你認爲合適,你可以發表你的評論作爲回答,因爲我覺得這個問題已經足夠了。 – ben 2014-10-22 14:16:29

回答

0

Postgres 可以使用除前導之外的其他列進行索引查找 - 這僅僅不如使用最左列的效率。 Postgres會在這種情況下掃描整個索引(而不是表格)。而對於最左列的條件,Postgres將僅檢索符合條件的索引中的那些行。效率的差異因此是處理的索引條目的數量。

我認爲這是某種隱藏在下面的句子from the manual背後:對這些列的右列

約束索引進行檢查,所以他們保存訪問表中正確的,但他們做的不會減少必須掃描的索引部分。

其中 「這些列」 指的是最左邊的列。


BTW:爲什麼timestamp(或datenumber)是一列這樣一個糟糕的選擇的原因是,它是一個保留字。但更重要的是:這個名字沒有記錄任何東西。不熟悉數據模型的人不知道你在那裏存儲什麼。消息發送的時間?收到消息的時間?郵件上次更新的時間?

+1

「Postgres將掃描整個索引」。我想我知道你的意思,但我不確定這種說法本身是否正確。如果在A,B,C上有一個索引,並且查詢在A,C上,那麼postgres將會掃描索引的整個B「級別」,但是例如它不一定會對完整的A級別進行掃描。 – ben 2014-10-22 15:49:04

+0

@ben:Postgres將掃描(即檢索)索引的所有**塊。沒有辦法只檢索'C'的值而不檢索'A' **和**'B' – 2014-10-22 15:52:24

+0

但是假設查詢在'WHERE'子句中包含'A = 3'。那麼是不是這樣,除了A級別上的A = 3'''上的所有其他分支,例如'A = 100',不必向下遍歷(通過B和C),因爲該分支的任何葉節點將保存一個肯定排除在查詢結果之外的值? – ben 2014-10-22 16:44:44