2014-10-22 49 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