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模糊匹配大杀器(推荐)

    postgresql模糊匹配大杀器(推荐)

    这篇文章主要介绍了postgresql模糊匹配大杀器,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • postgresql数据库执行计划图文详解

    postgresql数据库执行计划图文详解

    了解PostgreSQL执行计划对于程序员来说是一项关键技能,执行计划是我们优化查询,验证我们的优化查询是否确实按照我们期望的方式运行的重要方式,这篇文章主要给大家介绍了关于postgresql数据库执行计划的相关资料,需要的朋友可以参考下
    2024-01-01
  • Linux系统安装PostgreSQL数据库及配置的详细过程

    Linux系统安装PostgreSQL数据库及配置的详细过程

    这篇文章主要给大家介绍了关于Linux系统安装PostgreSQL数据库及配置的详细过程,PgSQL(全称PostgreSQL)是一个功能强大的开源对象-关系型数据库系统,结合了许多安全存储和扩展最复杂数据工作负载的功能,需要的朋友可以参考下
    2023-12-12
  • postgresql 除法保留小数位的实例

    postgresql 除法保留小数位的实例

    这篇文章主要介绍了postgresql 除法保留小数位的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • PostgreSQL自定义函数的使用

    PostgreSQL自定义函数的使用

    本文主要介绍了PostgreSQL自定义函数的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-06-06
  • postgresql限制某个用户仅连接某一个数据库的操作

    postgresql限制某个用户仅连接某一个数据库的操作

    这篇文章主要介绍了postgresql限制某个用户仅连接某一个数据库的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • PostgreSQL向量库pgvector的使用示例

    PostgreSQL向量库pgvector的使用示例

    本文主要介绍了PostgreSQL向量库pgvector的使用示例,pgvector是PostgreSQL的向量扩展,支持高达16000维向量存储及HNSW、IVFFlat索引,下面就来具体介绍一下
    2025-08-08
  • 安全高效的PostgreSQL数据库迁移解决方案

    安全高效的PostgreSQL数据库迁移解决方案

    PostgreSQL数据库是一款高度可扩展的开源数据库系统,支持复杂的查询、事务完整性和多种数据类型由于各种业务需求,企业常常需要将数据在不同的云平台或私有环境之间迁移,所以本文小编给大家介绍了安全高效的PostgreSQL数据库迁移解决方案,需要的朋友可以参考下
    2023-11-11
  • 基于PostgreSQL/openGauss 的分布式数据库解决方案

    基于PostgreSQL/openGauss 的分布式数据库解决方案

    ShardingSphere-Proxy 作为透明数据库代理,用户无需关心 Proxy 如何协调背后的数据库。今天通过本文给大家介绍基于PostgreSQL/openGauss 的分布式数据库解决方案,感兴趣的朋友跟随小编一起看看吧
    2021-12-12
  • PostgreSQL基础知识之SQL操作符实践指南

    PostgreSQL基础知识之SQL操作符实践指南

    这篇文章主要给大家介绍了关于PostgreSQL基础知识之SQL操作符实践的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用PostgreSQL具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2020-05-05

最新评论