如何在Postgres中索引表以加快ORDER BY

时间:2019-11-14 19:53:54

标签: postgresql postgresql-11

如何在PostgreSQL 11中创建索引以加速包含ORDER BY的特定查询?

我有一个查询,需要从包含2M条记录的表中获取前100条记录,以及一些常见的过滤器,例如:

SELECT id, first_name, last_name
FROM users
WHERE active = true AND region IN (1,2,3)
ORDER BY last_active_timestamp DESC;

没有ORDER BY子句,它将在约1秒内几乎立即返回。但是,使用该子句需要花费大约5分钟的时间。

所以我尝试创建像这样的部分索引:

CREATE INDEX CONCURRENTLY my_user_index ON users (active, region, last_active_timestamp DESC NULLS LAST)
WHERE region IN (1, 2, 3) AND active = True;

但是实际上没有任何效果。上面的查询仍然需要几分钟。这仅仅是Postgres中ORDER BY的限制,还是我可以使用另一种类型的索引来加快速度?

2 个答案:

答案 0 :(得分:0)

为了在查询中使用带有ORDER BY的索引,您需要在所有相关列(last_active_timestamp,以及仅包括active == true和区域a,b,c的条件上建立索引) )。从本质上来说,这将为您拉出数据。)

此外,如果共享EXPLAIN ANALYZE输出,则可能会看到Sort Method: external merge Disk: ####kB,这表明由于work_mem的大小不足,该排序溢出到了磁盘上,而不是内存中。然后,解决方案是将work_mem的值提高到至少####kB,然后重试。

请注意,您可以基于每个会话设置work_mem,因为work_mem中的全局更改可能会产生负面影响,例如内存不足,因为{{1} }配置的postgresql.conf被分配给每个会话(基本上,它具有乘法效果)。

如果调优work_mem后查询仍然很慢(也就是说,它全部在内存中排序,而且仍然很慢),那么您返回的数据集太大而无法快速排序。

答案 1 :(得分:0)

尝试索引是正确的,但是您使用了错误的索引。在此尝试:

CREATE INDEX CONCURRENTLY my_user_index
    ON users (last_active_timestamp DESC)
    WHERE region IN (1, 2, 3)
        AND active = true;

您的索引仅由last_active_timestampactive排序后,才由region进行排序,因此您不能仅使用索引来获得排序的输出。

为了提高速度,您还可以使用INCLUDE (id, first_name, last_name)将选择子句的列包括在索引中。现在,您的查询(如果计划者选择了,并且我认为会的话)可以只在索引上运行而根本不涉及表数据。