PostgreSQL性能:真正重要的索引策略

大多数PostgreSQL性能问题都是索引问题。这是解决大多数真实世界性能问题的索引策略实用指南。

为什么索引比硬件更重要

对1000万行表的顺序扫描检查每一行。有了适当的索引,相同的查询只触及相关行——可能少1,000倍。这种差异不能用更快的硬件来补偿:没有索引,快10倍的服务器仍然需要检查所有1000万行。理解查询执行计划(EXPLAIN ANALYZE)是有意义优化的前提。输出显示查询是否使用索引(Index Scan、Index Only Scan)或顺序扫描(Seq Scan),以及估计与实际行数。对于选择性查询,大表上的Seq Scan几乎总是表明缺少或未使用的索引。

B-Tree索引:默认

CREATE INDEX idx_users_email ON users(email) — 标准B-tree索引,适合:相等查找(WHERE email = ?)、范围查询(WHERE created_at BETWEEN ? AND ?)、已索引列上的ORDER BY,以及JOIN条件。B-tree索引支持所有比较运算符(<、<=、=、>=、>)。它们是绝大多数索引需求的正确选择。(user_id, created_at)上的复合索引可以满足仅在user_id上过滤或在user_id AND created_at上同时过滤的查询——但不能满足仅在created_at上过滤的查询(前导列规则)。设计复合索引时以最具选择性的过滤器或相等条件开始,然后是范围条件。

部分索引:常被忽视

部分索引只索引满足WHERE条件的行:CREATE INDEX idx_orders_pending ON orders(created_at) WHERE status = ‘pending’。如果你的表有1000万个订单,只有5万个是待处理的,部分索引小200倍,创建更快,查询更快,使用的磁盘空间和内存少得多。常见用例:只索引活动/未删除记录(软删除表)、只索引最近的数据、只索引查询实际需要找到的行子集。检查你最常见的查询是否有一个一致的WHERE条件,将其过滤到表的一小部分——如果是,部分索引可能是正确的优化。

N+1问题和索引使用

N+1查询问题(加载集合然后对每个项目进行一次查询以加载相关数据)产生许多单独快速的查询,这些查询集体降低了性能。示例:加载100个用户,然后为每个用户的订单查询orders表100次。修复:使用JOIN(在一个查询中加载所有数据)或在你的ORM中使用急切加载。为了使JOIN高效,相关表中的外键列必须被索引:CREATE INDEX idx_orders_user_id ON orders(user_id)。缺少外键索引是最常见的索引遗漏之一——许多ORM和模式工具不会自动创建它们。检查pg_stat_user_tables,查找seq_scan计数高和idx_scan计数低的表,作为查找缺失索引的起点。

上一篇 PostgreSQL Performance: The Index Strategies That Actually Matter
下一篇 Northern Portugal: Porto, the Douro Valley, and Vinho Verde Country