这是《PostgreSQL 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 BRIN 适合超大规模且物理顺序与时间或自增字段强相关的表;SP-GiST 适合空间划分、前缀和不平衡树结构。
10.1 BRIN
BRIN(Block Range Index)不索引每一行,而是记录连续数据块的范围摘要。
Block 1-128: min created_at = 08-01, max = 08-02
Block 129-256: min created_at = 08-02, max = 08-03
创建:
CREATE INDEX idx_events_created_brin
ON events USING BRIN (created_at);
查询:
SELECT count(*)
FROM events
WHERE created_at >= '2026-08-25'
AND created_at < '2026-08-26';
10.2 BRIN 适合场景
| 条件 | 说明 |
|---|---|
| 表很大 | 大表收益明显 |
| 物理顺序相关 | append-only 时间日志 |
| 查询范围明确 | 按时间窗口 |
| 索引空间敏感 | B-Tree 太大 |
| 可接受粗粒度 | 不要求精确定位 |
不适合随机写入后物理顺序混乱的数据,除非先按查询键重写。
10.3 BRIN 参数
CREATE INDEX idx_events_created_brin
ON events USING BRIN (created_at)
WITH (pages_per_range = 64);
| 参数 | 影响 |
|---|---|
| pages_per_range 小 | 更精准,索引更大 |
| pages_per_range 大 | 更小,扫描范围更粗 |
可以配置自动汇总:
ALTER TABLE events
SET (autosummarize = on);
10.4 SP-GiST
SP-GiST 支持空间划分树,适合数据天然可分区且不平衡的结构。
常见用途:
| 类型 | 用途 |
|---|---|
| text | 前缀匹配 |
| point | 空间划分 |
| inet | 网段 |
| range | 范围 |
前缀索引:
CREATE INDEX idx_hosts_prefix
ON hosts USING SPGIST (name prefix_ops);
网段:
CREATE INDEX idx_ip_network
ON access_log USING SPGIST (client_ip inet_ops);
10.5 索引选择
| 查询 | 首选 |
|---|---|
| 等值 / 范围 / 排序 | B-Tree |
| 纯等值高基数 | 可评估 HASH |
| JSON / 数组 / 全文 | GIN |
| 空间 / 范围重叠 | GiST |
| 大表时间 append | BRIN |
| 前缀 / 网段 / 划分结构 | SP-GiST |
10.6 验证索引效果
EXPLAIN (ANALYZE, BUFFERS)
SELECT *
FROM events
WHERE created_at >= now() - interval '1 hour';
观察:
- 扫描节点;
- Rows Removed by Filter;
- Shared Hit / Read;
- 执行时间;
- 索引大小。
本章小结
BRIN 用极小空间换取粗粒度过滤,适合顺序性强的大表。SP-GiST 面向可划分结构。索引选择先看数据分布和操作符,再看空间和写入成本。
思考题
- BRIN 为什么适合 append-only 日志表?
- pages_per_range 如何权衡?
- SP-GiST 适合什么数据结构?
- BRIN 如何验证扫描收益?
- 什么时候 B-Tree 优于 BRIN?