新闻详情

新闻详情

首页 / 资讯中心 / 详情

单列索引与多列索引:从典型查询看索引设计

发布时间:2026/9/26 9:08:02来源:尧图网络
单列索引与多列索引:从典型查询看索引设计
单列索引与多列索引从典型查询看索引设计文章目录单列索引与多列索引从典型查询看索引设计一、从一个常见查询说起二、单列索引是什么三、多列索引是什么四、最左前缀原则五、单列索引和多列索引的核心区别六、典型场景到底该建哪种索引场景 1只按一列查询场景 2固定组合条件查询场景 3组合条件 排序场景 4已有复合唯一约束最左列查询七、什么时候才需要额外建单列索引八、如何验证是否需要新建索引九、生产环境建索引建议十、总结在数据库优化中索引是最常用、也最容易用错的手段之一。很多人遇到慢查询时第一反应是“加个索引”但索引并不是越多越好。尤其是当表里已经有复合索引时再盲目加单列索引可能不仅没有收益还会增加写入成本、占用更多存储空间。本文从几个常见业务场景出发讲清楚单列索引和多列索引的区别以及什么时候该用哪种索引。一、从一个常见查询说起假设有一张订单表CREATETABLEorders(idbigintPRIMARYKEY,user_idbigintNOTNULL,statustextNOTNULL,created_attimestampNOTNULL,amountnumeric(18,2));常见查询可能有-- 查询某个用户的所有订单SELECT*FROMordersWHEREuser_id123;-- 查询某个用户已支付的订单SELECT*FROMordersWHEREuser_id123ANDstatusPAID;-- 查询某个用户已支付的订单按下单时间排序SELECT*FROMordersWHEREuser_id123ANDstatusPAIDORDERBYcreated_atDESC;面对这些查询应该建单列索引还是多列索引要回答这个问题先要理解两者的本质区别。二、单列索引是什么单列索引只包含一个列例如CREATEINDEXidx_orders_user_idONorders(user_id);它按照user_id排序。适合这类查询WHEREuser_id123WHEREuser_idIN(123,456,789)ORDERBYuser_id单列索引的优点是结构简单索引体积相对小对单列等值、范围、排序查询友好写入维护成本相对低。但它也有明显局限如果查询同时过滤多个列单列索引通常只能选其中一个使用或者通过多个单列索引做位图扫描效率不一定理想。三、多列索引是什么多列索引也叫复合索引它包含多个列例如CREATEINDEXidx_orders_user_status_createdONorders(user_id,status,created_at);这个索引不是简单地“同时给三列建索引”而是按照定义的顺序组织数据先按 user_id 排序 user_id 相同再按 status 排序 前两列相同再按 created_at 排序可以把它想象成电话簿先按姓氏排序姓氏相同再按名字排序。这种结构决定了复合索引的一个核心规则最左前缀原则。四、最左前缀原则对于复合索引(a,b,c)它能较好支持以下查询条件WHEREa?WHEREa?ANDb?WHEREa?ANDb?ANDc?WHEREa?ANDb?ANDc?-- c 通常不能有效缩小扫描范围但通常不能单独高效支持WHEREb?WHEREc?WHEREb?ANDc?原因很简单索引是先按a排序的。如果查询条件里没有a数据库很难直接定位到目标数据区域。所以复合索引的列顺序非常关键。一般建议等值过滤条件放前面范围过滤条件放后面排序字段可以放在最后尤其是与等值条件配合时选择性高的列不一定要放最前要结合查询模式综合判断。五、单列索引和多列索引的核心区别对比项单列索引多列索引包含列一列多列排序方式按该列排序按定义顺序逐列排序支持查询单列条件、排序组合条件、排序、覆盖索引最左前缀不涉及必须遵循索引体积通常较小通常较大写入成本较低较高冗余风险可能与复合索引最左列重复列顺序不合理时效果差适用场景高频单列查询固定组合查询、排序分页一句话概括单列索引解决“一列怎么查”的问题多列索引解决“多列怎么组合查、怎么排序”的问题。六、典型场景到底该建哪种索引场景 1只按一列查询SELECT*FROMordersWHEREuser_id123;如果这是最高频查询且没有其他复合索引可用那么可以建CREATEINDEXidx_orders_user_idONorders(user_id);场景 2固定组合条件查询SELECT*FROMordersWHEREuser_id123ANDstatusPAID;更合适的是复合索引CREATEINDEXidx_orders_user_statusONorders(user_id,status);因为数据库可以先定位user_id再在相同user_id内定位status效率通常比只用单列索引更好。场景 3组合条件 排序SELECT*FROMordersWHEREuser_id123ANDstatusPAIDORDERBYcreated_atDESC;可以考虑CREATEINDEXidx_orders_user_status_createdONorders(user_id,status,created_at);这样既能过滤又能利用索引顺序避免额外排序。场景 4已有复合唯一约束最左列查询很多表会有类似唯一约束UNIQUE(user_id,order_no)数据库会自动为它创建复合唯一索引(user_id, order_no)此时如果查询是WHEREuser_id123通常可以直接走这个复合唯一索引因为user_id是它的最左列。也就是说不一定需要再单独给user_id建一个单列索引。这是一个常见误区看到查询条件里只有user_id就立刻想建(user_id)单列索引。实际上如果已有(user_id, order_no)这样的复合索引单列索引很可能只是冗余。七、什么时候才需要额外建单列索引虽然复合索引的最左列可以支持单列查询但并不是所有情况都能完全替代单列索引。以下情况可以考虑额外建单列索引复合索引最左列不是该列例如已有索引(status, user_id)但高频查询是WHERE user_id ?。这时user_id不是最左列复合索引通常帮不上忙。复合索引太大单列索引更小、缓存更友好如果复合索引包含很多列体积很大而单列查询又极其高频单独建一个小索引可能减少 I/O。高频单列查询且现有复合索引选择性不足例如复合索引最左列基数很低单独查询该列时区分度差优化器可能更倾向全表扫描。外键列查询某些业务会频繁按外键列查询而现有复合索引的最左列不是该外键可能需要单独索引。实测证明现有索引不够快最终判断标准不是理论而是执行计划和实际耗时。八、如何验证是否需要新建索引不要凭感觉加索引先用执行计划验证。以 PostgreSQL 为例EXPLAIN(ANALYZE,BUFFERS)SELECT*FROMordersWHEREuser_id123;重点看是否出现Index Scan或Bitmap Index Scan使用了哪个索引actual rows和预估行数差异大不大Buffers显示读了多少数据块是否出现Seq Scan以及表有多大。如果执行计划已经走了已有的复合索引并且性能可接受就不需要再建单列索引。如果发现表很大查询很频繁现有索引没有用上或用了但扫描行数过多再考虑新建索引并继续用EXPLAIN ANALYZE对比优化前后效果。九、生产环境建索引建议避免冗余索引已有(a, b)时再建(a)通常是冗余的除非有明确实测理由。使用CONCURRENTLY创建索引PostgreSQL 中生产环境建议CREATEINDEXCONCURRENTLY idx_nameONtable_name(column_name);避免长时间锁表。关注索引使用情况可以通过pg_stat_user_indexes查看索引扫描次数找出长期未被使用的索引。考虑覆盖索引PostgreSQL 支持INCLUDECREATEINDEXidx_orders_user_status_includeONorders(user_id,status)INCLUDE(created_at,amount);可以减少回表但会增加索引体积。考虑部分索引如果只查询某类状态的数据CREATEINDEXidx_orders_active_userONorders(user_id)WHEREstatusACTIVE;索引更小维护成本更低。索引不是越多越好每个索引都会增加INSERT、UPDATE、DELETE的成本。写入频繁的表尤其要控制索引数量。十、总结单列索引和多列索引不是互相替代的关系而是服务于不同查询模式单列索引适合单列过滤、单列排序多列索引适合固定组合条件、组合排序、覆盖查询复合索引遵循最左前缀原则最左列可以支持单列查询但非最左列通常不能单独高效使用已有复合索引时不要习惯性再建最左列单列索引先看执行计划最终是否建索引要靠EXPLAIN ANALYZE和真实业务查询验证。索引设计的核心不是“多”而是“准”。理解查询模式合理安排列顺序避免冗余索引才能让数据库在读写之间取得更好的平衡。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

卒中患者六个月死亡预测实战 从医疗表格二分类到建模落地 2026/9/26 9:50:01

卒中患者六个月死亡预测实战 从医疗表格二分类到建模落地

这道 Kaggle 赛题聚焦卒中患者发病后 6 个月内是否死亡的预测,本质是医疗结局判断中的表格二分类任务。数据来自国际卒中试验,规模不大但任务边界清晰,适合用于演练从字段理解、标签确认、验证设计到结果提交的完整建模流程。 这类题目的价值不只在竞赛分数,更在于贴近真实…

阅读更多 →
BoolArt Cityscapes 语义分割实战解析 从街景感知到 Dice 优化 2026/9/26 9:49:55

BoolArt Cityscapes 语义分割实战解析 从街景感知到 Dice 优化

这篇案例围绕 BoolArt Cityscapes 展开,主题并不是泛泛而谈的视觉模型介绍,而是把一个自动驾驶街景语义分割题拆成可执行的工程问题。核心任务是在德国城市场景图像中识别道路、行人、骑行者及多类车辆,并输出符合提交规范的像素级结果。 内容重点放在任务理解、数据组织、…

阅读更多 →
UltraEdit 14.00b 注册码失效后,用 TaoToken 统一 Key 打通 AI 工具链的配置骨架 2026/9/26 9:49:55

UltraEdit 14.00b 注册码失效后,用 TaoToken 统一 Key 打通 AI 工具链的配置骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Jetpack Compose单选组件RadioButton正确用法与状态管理指南 2026/9/26 9:49:48

Jetpack Compose单选组件RadioButton正确用法与状态管理指南

1. 为什么单选组件值得单独拿出来写一篇先说个背景。Jetpack Compose 从 2021 年稳定到现在,很多团队已经用它重写了业务页面,但每次我看到网上流传的 Material 3 单选示例,十个里有八个还把RadioButton当“半成品按钮”在拼——selected 状态…

阅读更多 →
通信仿真代码合集|130+期原创案例,从通信基础到前沿领域仿真全覆盖(附获取方式) 2026/9/26 9:49:47

通信仿真代码合集|130+期原创案例,从通信基础到前沿领域仿真全覆盖(附获取方式)

我整理了一份无线通信案例设计及代码仿真合集,整整 16 个专栏,128 篇文章 🔥 热门方向全覆盖: ✅ 机器/深度学习赋能通信(CNN调制识别、LSTM信道估计、深度强化学习资源分配) ✅ 通感一体化 ISAC&#xff0…

阅读更多 →
Solidworks装配体保存为零件:合并实体操作全解析 2026/9/26 9:49:47

Solidworks装配体保存为零件:合并实体操作全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉