决策:选择哪种索引类型?
正确的索引类型取决于查询的访问模式(等值、范围或文本/JSON 搜索)、列的基数以及读写平衡。错误的索引既浪费空间又拖慢写入。这棵决策树从查询的形态出发,引导你在 B-tree、Hash、Bitmap、GIN/GiST、部分索引和覆盖索引之间做出选择,并提醒你复合索引中列的顺序至关重要。
你的查询如何使用这一列?
访问模式是选择索引最具决定性的因素。你只用 '=' 匹配该列,还是进行范围/排序(>、<、BETWEEN、ORDER BY),或者搜索全文、JSON 字段、几何数据/数组?从这里开始;在需求明确之前不要选择索引类型。
- 等值与范围/排序混合(=、>、<、BETWEEN、ORDER BY)
- 仅等值(=),无范围或排序
- 全文、JSON/JSONB 字段、数组或几何搜索
- 查询总是针对同一小部分行(例如 WHERE status='active')
该列的基数(不同值的数量)是多少?
如果需要范围/排序,默认选择 B-tree;但在读密集的数据仓库中,对于不同值很少的列(低基数:性别、状态、是/否),Bitmap 索引可能更好。该列有很多唯一值,还是少数重复值?
- 高基数(很多唯一值)或 OLTP 负载
- 低基数且读密集 / 数据仓库(DWH)
查询是否只读取索引中的列?
该访问模式适合 B-tree。最后一项优化:如果查询返回和过滤的所有列都在索引中,引擎可以只用索引回答而无需访问表(index-only / 覆盖扫描)。你的查询读取少数几列,还是需要大部分行数据?
- 是的,少数几列;无需访问表即可回答
- 不,标准访问即可
建议:B-tree(默认)
B-tree 是一种平衡树结构,支持多种访问模式:等值、范围、排序(ORDER BY)、使用 LIKE 'abc%' 的前缀匹配以及 MIN/MAX。它是大多数关系型引擎的默认索引类型,也是拿不准时的正确起点。
建议:Hash 索引(仅等值)
Hash 索引存储列值的哈希,只对精确等值('=')查找非常快。它不支持范围、排序或前缀搜索,因此适用场景很窄。
建议:Bitmap 索引(低基数 / DWH)
Bitmap 索引为每个不同的值维护一个位数组,并通过按位 AND/OR 极快地组合多个低基数条件。它在数据仓库和报表等读密集型负载中表现出色。
建议:GIN / GiST(文本、JSON、数组、几何)
PostgreSQL 为标准 B-tree 无法处理的访问类型提供了专门的索引家族。GIN 指向一个值内部的多个组成部分(词、JSONB 键、数组元素);GiST 适合几何/范围/最近邻等查询。
建议:部分索引 / 筛选索引
部分索引只对满足条件(WHERE ...)的行建立索引,而不是整张表。如果查询总是针对同一小部分行,索引会小得多、快得多,写入开销也会下降。
建议:覆盖(INCLUDE)索引
覆盖索引包含查询所需的所有列,使引擎只用索引就能回答,完全无需访问表(heap)(index-only scan)。对于频繁执行且返回列少的查询,速度提升显著。