Zha*_*eng 10 postgresql performance index sorting postgresql-9.4 postgresql-performance
我正在使用 postgres 9.4。
的messages具有以下模式:消息属于FEED_ID,并且具有posted_at,还消息可以具有(在答复的情况)的父消息。
Table "public.messages"
Column | Type | Modifiers
------------------------------+-----------------------------+-----------
message_id | character varying(255) | not null
feed_id | integer |
parent_id | character varying(255) |
posted_at | timestamp without time zone |
share_count | integer |
Indexes:
"messages_pkey" PRIMARY KEY, btree (message_id)
"index_messages_on_feed_id_posted_at" btree (feed_id, posted_at DESC NULLS LAST)
Run Code Online (Sandbox Code Playgroud)
我想返回由 排序的所有消息share_count,但对于每个parent_id,我只想返回一条消息。即,如果多条消息具有相同的parent_id,则仅posted_at返回最新的一条 ( )。在parent_id可以为空,以空消息parent_id都应该回报。
我使用的查询是:
WITH filtered_messages AS (SELECT *
FROM messages
WHERE feed_id IN (7)
AND (posted_at >= '2015-01-01 04:00:00.000000')
AND (posted_at < '2015-04-28 04:00:00.000000'))
SELECT *
FROM (SELECT DISTINCT ON(COALESCE(parent_id, message_id)) parent_id,
message_id,
posted_at,
share_count
FROM filtered_messages
ORDER BY COALESCE(parent_id, message_id), posted_at DESC NULLS LAST
) messages
ORDER BY share_count DESC NULLS LAST, posted_at DESC NULLS LAST;
Run Code Online (Sandbox Code Playgroud)
这是http://sqlfiddle.com/#!15/588e5/1/0,在 SQL Fiddle 中,我已经定义了架构、确切的查询和预期的结果。
但是一旦消息表变大,查询的性能就会变慢。我尝试添加多个排序索引,但它似乎没有使用索引。这是解释:http : //explain.depesz.com/s/Sv2
如何创建正确的索引?
Erw*_*ter 11
在任何情况下,此查询都应该快得多:
SELECT parent_id, message_id, posted_at, share_count
FROM messages
WHERE feed_id = 7
AND posted_at >= '2015-01-01 4:0:0'
AND posted_at < '2015-04-28 4:0:0'
AND parent_id IS NULL -- match index condition
UNION ALL
(
SELECT DISTINCT ON(parent_id)
parent_id, message_id, posted_at, share_count
FROM messages
WHERE feed_id = 7
AND posted_at >= '2015-01-01 4:0:0'
AND posted_at < '2015-04-28 4:0:0'
AND parent_id IS NOT NULL -- match index condition
ORDER BY parent_id, posted_at DESC NULLS LAST
)
ORDER BY share_count DESC NULLS LAST, posted_at DESC NULLS LAST;
Run Code Online (Sandbox Code Playgroud)
CTE 在这里没有做任何普通子查询也无法提供的事情。并且 CTE 引入了优化障碍,因为它是单独执行的并且其结果是具体化的。
您拥有比实际需要的更多的子查询级别。
该表达式(COALESCE(parent_id, message_id)与普通索引不兼容,您需要该表达式的索引。但这也可能不是很有用,这取决于数据分布。按照我下面的链接获取详细信息。
将 的简单情况拆分parent_id IS NULL为单独的情况SELECT可能会也可能不会提供最佳效果。尤其不是,如果无论如何这是一种罕见的情况,在这种情况下,带有索引的组合查询(COALESCE(parent_id, message_id)可能会表现得更好。其他注意事项适用...
特别是当这些索引支持时:
CREATE INDEX messages_idx_null ON messages (
feed_id
, posted_at DESC NULLS LAST
, share_count DESC NULLS LAST
, parent_id, message_id
)
WHERE parent_id IS NULL;
CREATE INDEX messages_idx_notnull ON messages (
feed_id
, posted_at DESC NULLS LAST
, share_count DESC NULLS LAST
, parent_id, message_id
)
WHERE parent_id IS NOT NULL;
Run Code Online (Sandbox Code Playgroud)
这两个部分索引一起覆盖了整个表,并且与单个总索引的大小大致相同。
最后两列parent_id, message_id只有在您从中获得仅索引扫描时才有意义。否则,将它们从两个索引中删除。
根据缺失的细节,DISTINCT ON可能是也可能不是用于此目的的最佳查询技术。在此处阅读详细说明:
可能还有更快的替代方案: