如何在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
的限制,还是我可以使用另一种类型的索引来加快速度?
答案 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_timestamp
和active
排序后,才由region
进行排序,因此您不能仅使用索引来获得排序的输出。
为了提高速度,您还可以使用INCLUDE (id, first_name, last_name)
将选择子句的列包括在索引中。现在,您的查询(如果计划者选择了,并且我认为会的话)可以只在索引上运行而根本不涉及表数据。