TL;DR
运行以下三个命令,查看问题是否解决:
ANALYZE;
SET random_page_cost = 1.0;
SET effective_cache_size = 'X GB'; # replace X with total RAM size minus 2 GB
继续阅读以了解更多详细信息和背景信息。
第 1 步:分析表格
作为解决问题的简单第一次尝试,以数据库超级用户身份运行ANALYZE; 命令以更新所有表统计信息。来自documentation:
查询计划器使用这些统计信息来帮助确定最有效的查询执行计划。
第 2 步:设置正确的随机页面费用
索引扫描需要非顺序的磁盘页面获取。 PostgreSQL 使用random_page_cost 配置参数来估计这种非顺序提取相对于顺序提取的成本。来自documentation:
减少这个值 [...] 将导致系统更喜欢索引扫描;提高它会使索引扫描看起来相对更昂贵。
默认值为4.0,因此假设与顺序提取相比,平均成本因子为 4,同时考虑到缓存效果。但是,如果您的数据库存储在 SSD 驱动器上,那么您实际上应该根据文档将 random_page_cost 设置为 1.1:
相对于顺序存储(例如固态驱动器)具有较低随机读取成本的存储,也可以使用较低的 random_page_cost 值(例如 1.1)更好地建模。
此外,如果索引大部分(甚至完全)缓存在 RAM 中,那么索引扫描将始终显着比磁盘服务的顺序扫描快。然而,查询规划器不知道索引的哪些部分已经被缓存,因此可能会做出错误的决定。
如果您的数据库索引被频繁使用,并且系统有足够的 RAM,那么索引最终可能会被缓存。在这种情况下,random_page_cost 可以设置为1.0,或者甚至设置为低于1.0 的值,以积极地使用索引扫描(尽管文档建议不要这样做)。您必须尝试不同的值,看看哪种值适合您。
附带说明一下,您还可以考虑使用 pg_prewarm 扩展将您的索引显式缓存到 RAM 中。
您可以像这样设置random_page_cost:
SET random_page_cost = 1.0;
第 3 步:设置正确的缓存大小
在具有 8 GB 或更多 GB RAM 的系统上,您应该将 effective_cache_size 配置参数设置为 PostgreSQL 通常可用于数据缓存的内存量。来自documentation:
值越大,使用索引扫描的可能性越大,值越低,使用顺序扫描的可能性越大。
请注意,此参数不会更改 PostgreSQL 实际分配的内存量,而仅用于计算成本估算。一个合理的值(至少在专用数据库服务器上)是总 RAM 大小减去 2 GB。默认值为4 GB。
您可以像这样设置effective_cache_size:
SET effective_cache_size = '14 GB'; # e.g. on a dedicated server with 16 GB RAM
第 4 步:永久修复问题
您可能希望使用ALTER SYSTEM SET ... 或ALTER DATABASE db_name SET ... 永久设置新的配置参数值(全局或每个数据库)。参数设置详见documentation。
第 5 步:其他资源
如果还是不行,那么你可能还想看看this PostgreSQL Wiki page about server tuning。