假设我在PostgreSQL数据库中有一个包含许多条目的messages
表。该表的主键只是一个简单的serial
列(如int
,但带有“自动增量”)。
然后我想选择用户收到并符合特定条件的TOP-25消息。结果按唯一主键列(msgid DESC
)排序。
-- EXPLAIN ANALYZE
SELECT msgid, msgtype, created, msgtitle, recvuser, readbyrecv, someothercolumn, onemorecolumn
FROM xyz.messages
WHERE ( ( msgtype = 42 ) OR ( msgtype = 1337 ) )
AND ( recvuser = 123 ) AND ( hiddenbyrecv = false )
ORDER BY msgid DESC
LIMIT 25 OFFSET 0
我有一个像这样的过滤索引:
CREATE INDEX ix_abcde
ON xyz.messages
USING btree (msgtype, recvuser, hiddenbyrecv, msgid DESC)
WHERE (msgtype = 42 OR msgtype = 1337) AND hiddenbyrecv = false;
我认为索引应该包含WHERE
和ORDER
子句中使用的所有列。
如果我运行SELECT 而不用 LIMIT 25 OFFSET 0
(该行已注释掉),则正在使用索引并且查询非常快(大约2ms) ):
-- EXPLAIN ANALYZE
SELECT msgid, msgtype, created, msgtitle, recvuser, readbyrecv, someothercolumn, onemorecolumn
FROM xyz.messages
WHERE ( ( msgtype = 42 ) OR ( msgtype = 1337 ) )
AND ( recvuser = 123 ) AND ( hiddenbyrecv = false )
ORDER BY msgid DESC
-- LIMIT 25 OFFSET 0
但是如果我使用来查询 LIMIT和OFFSET子句(请参阅第一个SQL查询),它会向后扫描表的主键并执行全表扫描。索引未使用。该查询的时间超过 100倍(> 200ms)。
由于msgid
是唯一的(主键),我认为PostgreSQL应该能够使用索引确定性地找到此列所排序的TOP 25条目。我按正确的顺序在索引中包含了唯一的ORDER BY列。
我错过了什么?你能给我一些提示吗?
//编辑:服务器从Debian存储库运行标准的PostgreSQL 9.4版本包。