PostgreSQL 六大索引的方法小结

 更新时间:2025年11月12日 10:31:58   作者:Hello.Reader  
本文主要介绍了PostgreSQL 六大索引的方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、概览速览表(先有直觉)

索引类型典型用途支持唯一适配查询优缺点一眼看
B-tree等值、范围、排序、唯一约束=, <, >, BETWEEN, ORDER BY默认首选,通用;维护成本中等
Hash纯等值匹配❌(唯一约束由 B-tree 实现)=仅等值;自 PG10 起 WAL 持久化;使用面窄
GIN倒排类:jsonb、数组、全文、trigram@>, ?, ?&, @@(全文),LIKE/ILIKE(trigram)读快写慢,适合查询多、更新少
GiST距离/范围/空间/相似度、KNN范围、相交、<-> KNN通用“框架”,支持多种数据类型(几何、range、inet…)
SP-GiST前缀/空间分割(trie/k-d/四叉树)前缀、某些 KNN适合强分割数据(前缀搜索、坐标)
BRIN超大表顺序相关列(时间/自增ID)大范围扫描的快速剪枝体积极小,建立/维护极轻;精度低需回检

记忆法:“B 通吃、H 等值、GIN 倒排、GiST 空间、SPG 前缀、BRIN 顺序”

二、B-tree(默认 & 通吃)

特性

  • PostgreSQL 的 UNIQUE/主键约束本质上都是 B-tree 索引。
  • 适配等值/范围/排序/聚合的常见访问路径与 ORDER BY … LIMIT
  • 支持覆盖索引INCLUDE,用于只读回表字段;主要用于 B-tree)。

常用语法

-- 单列 / 多列
CREATE INDEX idx_user_email ON users(email);
CREATE INDEX idx_orders_user_created ON orders(user_id, created_at DESC);

-- 覆盖索引(减少回表)
CREATE INDEX idx_orders_status_created_inc
ON orders(status, created_at)
INCLUDE (amount);

-- 表达式/部分索引
CREATE INDEX idx_lower_email ON users (lower(email));
CREATE INDEX idx_paid_recent ON orders (created_at)
WHERE status = 'PAID';

实战要点

  • 多列 B-tree 的左前缀原则:查询条件要尽量命中前导列。
  • 大量 LIKE 'abc%'前缀匹配通常也可命中 B-tree;但包含式 %abc%pg_trgm
  • 注意 NULL:唯一约束允许多行 NULL。

三、Hash(只做“等值”)

场景:极端等值查找且键宽/比较代价特殊时,可能略小/略快。
限制:不支持唯一约束与范围/排序;面窄,大多数等值场景仍用 B-tree

CREATE INDEX idx_users_hash_email ON users USING hash(email);

备注:自 PG10 起 Hash 索引 WAL 持久化,可崩溃恢复,但优势有限。

四、GIN(倒排:jsonb/数组/全文/trigram)

场景

  • jsonb 包含/键值查询:@>, ?, ?&
  • 数组元素包含/交集;
  • 全文检索 to_tsvector(...) @@ to_tsquery(...)
  • 模糊查询:pg_trgm 的 trigram + LIKE/ILIKE '%abc%'

语法与 opclass

-- jsonb:两种常用 opclass
CREATE INDEX idx_doc_gin ON docs USING gin(data jsonb_ops);       -- 全功能,体积偏大
CREATE INDEX idx_doc_path ON docs USING gin(data jsonb_path_ops);  -- 对 @> 优化更好

-- 数组包含
CREATE INDEX idx_tags_gin ON posts USING gin(tags);

-- 全文
CREATE INDEX idx_posts_fts ON posts USING gin(to_tsvector('simple', title || ' ' || body));

-- trigram 模糊(需扩展)
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE INDEX idx_user_name_trgm ON users USING gin(name gin_trgm_ops);

调优

-- 批量重放/更新多时:构建或维护参数
CREATE INDEX ... USING gin(...) WITH (fastupdate = on, gin_pending_list_limit = '512MB');
  • 优点:读极快(特别是包含/全文/模糊);
  • 缺点:写慢、体积大;更适合“读多写少”或批量导入。

五、GiST(“通用”搜索树:空间/范围/KNN/排斥约束)

场景

  • 几何/地理(PostGIS)、rangeinet/cidr、相交/包含等;
  • KNN 最近邻查询:ORDER BY <->
  • 排斥约束(Exclusion Constraint):避免时间段/空间重叠(常配合 btree_gist)。

示例

-- 范围不重叠的预约(时间区间)
CREATE EXTENSION IF NOT EXISTS btree_gist;

CREATE TABLE booking(
  room_id int,
  during tstzrange,
  EXCLUDE USING gist (room_id WITH =, during WITH &&)  -- 禁止同房间时间相交
);

-- KNN:最近地点
CREATE INDEX idx_poi_gist ON poi USING gist (geom);
SELECT * FROM poi ORDER BY geom <-> ST_SetSRID(ST_MakePoint(121.5,31.2), 4326) LIMIT 20;

要点

  • GiST 是“框架”,性能取决于具体 operator class(几何、range 等)。
  • 构建大索引可:WITH (buffering = on);范围型查询常见“回检”。

六、SP-GiST(空间分割/前缀)

场景

  • 前缀类数据(如手机号/URL/域名前缀)基于 trie;
  • 坐标点的 k-d/四叉树等强分割结构。
-- 前缀查询
CREATE INDEX idx_phone_prefix ON users USING spgist (phone_number);
SELECT * FROM users WHERE phone_number LIKE '1389%';

特点:对分布不均匀且可递归分割的数据更友好;更新/插入性能通常优于 GiST 的某些场景。

七、BRIN(Block Range Index:大表“顺序相关”神器)

场景

  • 超大表(千万/亿级),created_at、自增 id 与物理顺序相关性高
  • 大范围查询或分段扫描,BRIN 能以极小代价快速缩小扫描页面。
-- 典型配置:pages_per_range 控制摘要粒度(越小越精细)
CREATE INDEX idx_orders_brin_created
  ON orders USING brin (created_at)
  WITH (pages_per_range = 128, autosummarize = on);

要点

  • BRIN 只存储每个范围的 min/max 等摘要,需要回表回检
  • 体积/维护成本极低,适合“追加写 + 时间窗口查询”;
  • 相关性弱(数据经常乱序写入)时效果下降,可 CLUSTER/重写表优化物理顺序。

八、选型决策 10 条军规

  1. 能用 B-tree 先用 B-tree:等值/范围/排序/唯一都稳。
  2. jsonb/数组/全文/模糊GIN;其中 LIKE '%abc%' 强烈建议 trigram + GIN
  3. 距离/空间/范围相交/KNN → GiST(PostGIS、range、inet 等)。
  4. 前缀或可分割空间结构 → SP-GiST
  5. 超大追加型时间/ID查询 → BRIN
  6. 纯等值且确有收益证据 → Hash;否则 B-tree。
  7. 高频过滤 + 低选择度 → 部分索引WHERE ...)胜过大而全。
  8. 只读回表字段较多 → B-tree INCLUDE 做覆盖扫描。
  9. 表达式要索引同款表达式(如 lower(email));否则无法命中。
  10. 多列顺序要按查询使用频次/选择度从左到右排列;避免“全吃不着”的复合索引。

九、常见坑与对症下药

  • 模糊查询没走索引LIKE '%abc%'pg_trgm + GIN/GiSTLIKE 'abc%' 可走 B-tree。
  • 大小写不敏感lower(col) 表达式索引 + 查询同写法;或用 citext 类型。
  • 多列索引未命中:条件没用到前导列;或使用了不等价的表达式/函数。
  • jsonb 慢:选对 opclass:jsonb_path_ops@> 更紧凑;更新频繁则谨慎使用 GIN。
  • 索引暴胀:定期 VACUUM,必要时 REINDEX;控制 fillfactor
  • 计划不稳定:检查统计信息与相关性(ANALYZEdefault_statistics_target);利用 EXPLAIN (ANALYZE, BUFFERS) 诊断。

十、实战模板:一张订单表怎么配索引

CREATE TABLE orders(
  id           bigserial PRIMARY KEY,
  user_id      bigint NOT NULL,
  status       text   NOT NULL,
  created_at   timestamptz NOT NULL DEFAULT now(),
  amount       numeric(12,2) NOT NULL,
  items        jsonb,             -- 订单明细(jsonb)
  tags         text[]             -- 标签
);

-- 1) 用户最近订单(分页/排序)
CREATE INDEX idx_orders_user_created ON orders(user_id, created_at DESC);

-- 2) 状态 + 时间窗口统计(覆盖金额)
CREATE INDEX idx_orders_status_created_inc
  ON orders(status, created_at)
  INCLUDE (amount);

-- 3) jsonb 包含查找(items 内含某 SKU)
CREATE INDEX idx_orders_items_path ON orders USING gin(items jsonb_path_ops);

-- 4) 标签包含任一/全部
CREATE INDEX idx_orders_tags_gin ON orders USING gin(tags);

-- 5) 超大表时间过滤的剪枝
CREATE INDEX idx_orders_brin_created
  ON orders USING brin (created_at) WITH (pages_per_range=128, autosummarize=on);

十一、性能与维护清单

  • 分析与观测EXPLAIN (ANALYZE, BUFFERS), pg_stat_statements, pg_stat_all_indexes
  • 维护VACUUM (ANALYZE)、高写入期适当增大 maintenance_work_mem;大索引可并行创建:CREATE INDEX CONCURRENTLY(无锁长事务,但更慢)。
  • 参数提示:顺序 I/O 多可调低 random_page_cost;SSD 环境可适当下调以提高索引倾向。
  • 物理顺序:时间序列表可偶尔 CLUSTER 或重写,提高 BRIN/JIT 效果与热点局部性。

十二、快速对照:你在查什么,就选什么

  • WHERE a = ? / ORDER BY a / BETWEENB-tree
  • WHERE col @> '{"k":"v"}'::jsonb / tags @> '{x}'GIN(jsonb/数组)
  • title @@ to_tsquery('...')GIN(全文)
  • name ILIKE '%abc%'GIN + pg_trgm
  • geom <-> point 最近点 → GiST + KNN
  • tsrange && ? 不重叠预约 → GiST + 排斥约束
  • phone LIKE '1389%'SP-GiST(或 B-tree 也可)
  • WHERE created_at BETWEEN ...(亿级表) → BRIN

到此这篇关于PostgreSQL 六大索引的方法小结的文章就介绍到这了,更多相关PostgreSQL 索引内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • PostgreSQL实现交叉表(行列转换)的5种方法示例

    PostgreSQL实现交叉表(行列转换)的5种方法示例

    这篇文章主要给大家介绍了关于PostgreSQL实现交叉表(行列转换)的5种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-08-08
  • PostgreSQL中进行数据导入和导出的示例代码

    PostgreSQL中进行数据导入和导出的示例代码

    在数据库管理中,数据的导入和导出是非常常见的操作,特别是在 PostgreSQL 中,提供了多种工具和方法来实现数据的有效管理,本文将详细介绍在 PostgreSQL 中如何进行数据导入和导出,并给出具体的命令及示例,需要的朋友可以参考下
    2026-03-03
  • PostgreSQL数据库中如何保证LIKE语句的效率(推荐)

    PostgreSQL数据库中如何保证LIKE语句的效率(推荐)

    这篇文章主要介绍了PostgreSQL数据库中如何保证LIKE语句的效率,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • PostgreSQL中实现数据实时监控和预警的步骤详解

    PostgreSQL中实现数据实时监控和预警的步骤详解

    在 PostgreSQL 中实现数据的实时监控和预警是确保数据库性能和数据完整性的关键任务,以下将详细讨论如何实现此目标,并提供相应的解决方案和具体示例,需要的朋友可以参考下
    2024-07-07
  • PostgreSQL 安装部署及配置使用教程

    PostgreSQL 安装部署及配置使用教程

    PostgreSQL是一个功能强大的开源对象关系型数据库系统,支持 SQL 标准和扩展,适合各种规模应用,本文给大家介绍PostgreSQL 安装部署及配置使用,感兴趣的朋友跟随小编一起看看吧
    2025-11-11
  • PostgreSQ数据库实现在Windows上异地自动备份指南的详细教程

    PostgreSQ数据库实现在Windows上异地自动备份指南的详细教程

    这篇文章主要为大家详细介绍了如何在Windows系统上实现PostgreSQL数据库的异地自动备份,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下
    2025-12-12
  • navicat无法连接postgreSQL-11的解决方案

    navicat无法连接postgreSQL-11的解决方案

    这篇文章主要介绍了navicat无法连接postgreSQL-11的解决方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • postgreSQL自动生成随机数值的实例

    postgreSQL自动生成随机数值的实例

    这篇文章主要介绍了postgreSQL自动生成随机数值的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • postgresql 日期查询最全整理

    postgresql 日期查询最全整理

    这篇文章主要介绍了postgresql 日期查询最全整理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-08-08
  • 开源数据库postgreSQL13在麒麟v10sp1源码安装过程详解

    开源数据库postgreSQL13在麒麟v10sp1源码安装过程详解

    这篇文章主要介绍了开源数据库postgreSQL13在麒麟v10sp1源码安装过程详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01

最新评论