当前位置: 首页 > news >正文

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_createdON 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_incON 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_createdON 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
http://www.dtcms.com/a/544691.html

相关文章:

  • 2025年--Lc224--100. 相同的树(递归,dfs,带测试用例)-Java版
  • Python打造美观的桌面温馨提醒弹窗
  • 北京网站制作建设太原it培训机构
  • certbot+shell+阿里云api+k8s实现自动化更新SSL证书
  • Linux小课堂: 系统核心技能与应用总结与进阶指南
  • 前端vue项目在vscode使用插件部署到服服务器的方法
  • 使用Labelimg进行图像标注
  • 【计算机软件资格考试】软考案例分析题及解析模拟题10
  • IoTDA应用侧app开发403报错解决方案
  • 3.1 Lua代码中的元表与元方法
  • Rust——多重借用的冲突解决方案:驾驭Rust借用检查器的艺术
  • kaggle比赛与常用的dash board 3lc
  • 适配器模式:让不兼容的接口协同工作
  • Neo4j中导入.owl数据
  • 应急救援 “眼观六路”:SA/NSA 双模覆盖,偏远灾区也能实时传视频
  • 站长工具短链接生成网站中队人物介绍怎么做
  • 【Spring Boot + Spring Security】从入门到源码精通:藏经阁权限设计与过滤器链深度解析
  • 《嵌入式硬件(十七):基于IMX6ULL的温度传感器LM75a操作》
  • 用 Go 手搓一个内网 DNS 服务器:从此告别 IP 地址,用域名畅游家庭网络!
  • Rust async/await 语法糖的展开原理:从表象到本质
  • Rust 零拷贝技术:从所有权到系统调用的性能优化之道
  • 浪潮服务器装linux系统步骤
  • 视频网站服务器带宽需要多少?视频网站服务器配置要求
  • 《嵌入式硬件(十八):基于IMX6ULL的ADC操作》
  • 注册网站发财的富豪北京公司如何做网站
  • 仓颉语言异常捕获机制深度解析
  • 基于SAP.NET Core Web APP(MVC)的医疗记录管理系统完整开发指南
  • 咖啡网站建设设计规划书wordpress修改首页网址导航
  • C#WPF UI路由事件:事件冒泡与隧道机制
  • 神经网络时序预测融合宏观变量的ETF动态止盈系统设计与实现