索引体系
PostgreSQL 的索引体系远超传统关系库的 B-tree,五种索引覆盖从 OLTP 精确查找到全文、空间、时序的全场景。面试主线:五种索引各解决什么问题,什么时候用哪种。
五种索引
| 索引 | 底层 | 擅长 | 适用 |
|---|---|---|---|
| B-tree | 平衡树 | 等值、范围、排序、前缀 | 默认,绝大多数场景 |
| GIN | 倒排索引 | 包含查询:数组、jsonb、全文检索 | 多值类型 |
| GiST | 通用搜索树 | 空间、范围、最近邻 | PostGIS、几何数据 |
| BRIN | 块范围摘要 | 物理顺序相关的大表 | 时序、日志(TB 级) |
| Hash | 哈希桶 | 纯等值 | 基本被 B-tree 取代 |
B-tree是默认主力:支持等值、范围、排序、LIKE 'abc%' 前缀。多列索引遵循最左前缀(和 MySQL 相同)。INCLUDE 子句加非索引列实现覆盖索引(Index-Only Scan)。部分索引(WHERE 子句限定行集)和表达式索引(如 to_tsvector 表达式)是两个常用利器。
GIN:把多值拆成词位建倒排,数组 @>、jsonb 的 @> 和 ?、全文检索 @@ 都靠它。读快写慢(一个值更新多处 posting list),fastupdate 用 pending list 缓冲写入。
GiST:平衡树框架,节点存谓词(bounding box),查询按谓词剪枝。PostGIS 空间索引、范围类型、最近邻(<-> 距离排序)都靠它。
BRIN:不为每行建索引,而是为一组连续页(默认 128 页)存 min/max 摘要。对物理顺序与查询条件强相关的大表(时间序列),索引大小是 B-tree 的千分之一,查询时快速排除无关页范围。数据随机分布时退化为全表扫描,别用。
pgvector
pgvector 扩展提供向量类型和索引:
vector类型 + 余弦/内积/L2 距离- IVFFlat:先聚类再检索,建索引快,召回略低
- HNSW:图索引,召回高,内存占用大
- 适合千万级以内的向量检索,RAG 场景的轻量选择
超过千万级或要极低延迟,才考虑专门的向量库(Milvus 等)。pgvector 的优势是和业务数据同库,事务和过滤原生支持。
与 MySQL 的对比
| 维度 | PostgreSQL | MySQL |
|---|---|---|
| 索引类型 | B-tree/GiST/GIN/BRIN/Hash | B+树/哈希/全文 |
| 全文检索 | GIN 原生支持 | 全文索引弱,常用 ES |
| 空间索引 | GiST 成熟 | 支持有限 |
| 覆盖索引 | INCLUDE 子句 | 联合索引隐式实现 |
| 向量检索 | pgvector | 无 |
面试追问
- 五种索引怎么选? 等值范围排序用 B-tree,数组和 jsonb 用 GIN,空间用 GiST,顺序大表用 BRIN
- GIN 和 GiST 全文检索怎么选? GIN 读快写慢体积大适合读多写少;GiST 写快读慢体积小适合更新频繁
- BRIN 什么时候有效? 数据物理顺序与查询条件强相关(时间序列)。顺序乱了就退化为全表扫描
- pgvector 的 HNSW 和 IVFFlat? HNSW 图索引召回高内存大,IVFFlat 聚类索引建得快召回略低
- PG 的覆盖索引怎么写? B-tree 加 INCLUDE 子句附加非查找列,Index-Only Scan 免回表