MySQL 索引设计的原则

ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花

MySQL索引是提升查询效率的核心手段,合理的索引设计能避免全表扫描、减少IO开销,而不合理的索引不仅无法优化性能,还会增加数据写入(插入、更新、删除)的成本,占用额外存储空间。设计索引需遵循“高效、实用、精简”的核心思路,具体原则如下:

一、优先为高频查询字段建立索引

索引的核心价值是加速查询,因此需优先为查询频率高、过滤性强的字段建立索引。比如用户表的user_id(主键,高频用于查询单个用户)、订单表的order_no(唯一索引,高频用于查询订单详情)、商品表的category_id(高频用于按分类筛选商品)。

反例:为低频查询的字段(如用户表的last_login_ip,仅偶尔统计时使用)建立索引,会浪费存储空间,且增加写入时的索引维护成本。

二、遵循“最左前缀原则”设计联合索引

当查询条件包含多个字段时,优先使用联合索引而非多个单列索引(联合索引可减少索引数量,降低维护成本),且需遵循“最左前缀原则”——联合索引的生效顺序由左至右,查询时需从最左侧字段开始匹配,否则索引会失效。

示例:若建立联合索引(a, b, c),则查询条件包含aa AND ba AND b AND c时索引生效;仅包含bcb AND c时,索引不生效。

注意:联合索引的字段顺序需结合查询场景,将过滤性最强、查询频率最高的字段放在最左侧(比如查询频繁为WHERE a=? AND b=?,且a的区分度更高,则a放左侧)。

三、避免过度索引

索引并非越多越好,每增加一个索引,MySQL在执行插入、更新、删除操作时,都需要同步更新对应的索引结构,会显著降低写入性能;同时,过多的索引会占用大量存储空间,还可能导致MySQL优化器选择错误的索引(索引过多时,优化器判断成本升高)。

建议:单张表的索引数量控制在5-8个以内,删除无用、冗余的索引(如与联合索引最左前缀重复的单列索引,若有联合索引(a, b),则单列索引a属于冗余索引)。

四、选择区分度高的字段作为索引

字段的区分度( cardinality )指字段中不同值的数量占比,区分度越高,索引的过滤效果越好,能快速定位到目标数据,减少扫描行数。

示例:用户表的user_id(唯一值,区分度100%)适合建立索引;而gender(仅男、女、未知三个值,区分度极低)不适合建立索引——即使建立索引,MySQL也可能选择全表扫描(因为过滤后的数据量依然很大,索引查询的开销高于全表扫描)。

注意:区分度的判断可通过SELECT COUNT(DISTINCT 字段名) / COUNT(*) FROM 表名计算,比值越接近1,区分度越高。

五、避免对索引字段进行函数/表达式操作

若查询条件中对索引字段进行函数、表达式或类型转换操作,会导致MySQL无法使用该索引(索引失效),进而触发全表扫描。

反例:SELECT * FROM user WHERE SUBSTR(username, 1, 3) = 'abc'(对索引字段username使用SUBSTR函数)、SELECT * FROM order WHERE create_time + INTERVAL 7 DAY > NOW()(对索引字段create_time进行表达式操作)。

正例:将函数操作转移到查询值上,如SELECT * FROM user WHERE username LIKE 'abc%'(模糊查询前缀匹配,索引生效)、SELECT * FROM order WHERE create_time > NOW() - INTERVAL 7 DAY

六、优先使用覆盖索引,减少回表

覆盖索引是指索引中包含了查询所需的所有字段(即“查询字段 ≤ 索引字段”),此时MySQL无需通过索引定位到数据行后再去读取数据表(回表操作),直接从索引中即可获取所有所需数据,大幅提升查询效率。

示例:若建立索引(id, username, phone),查询SELECT id, username FROM user WHERE id > 100时,无需回表,直接从索引中读取数据。

建议:结合高频查询的字段,设计包含查询所需字段的联合索引,避免“select *”(会导致无法使用覆盖索引,必须回表)。

七、考虑索引的维护成本,适配业务场景

索引的维护成本与数据写入频率正相关:写入频繁(如订单表、日志表)的表,应尽量减少索引数量(避免每次写入都同步更新多个索引);读取频繁、写入较少(如商品表、字典表)的表,可适当增加索引,提升查询效率。

此外,对于大数据量的表,避免建立过长的索引(如 varchar(255) 字段),可通过截取字段前缀建立索引(如INDEX idx_name (name(10))),平衡索引效率和存储空间(前缀长度需根据字段区分度调整,避免过短导致区分度不足)。

八、主键索引优先选择自增整数型

MySQL的InnoDB引擎中,主键索引是聚簇索引(数据行与索引结构绑定),选择自增整数型(如INT、BIGINT)作为主键,有两个核心优势:

  • 自增主键能保证新插入的数据行始终追加在索引末尾,避免索引页分裂(若主键为随机值,新数据会插入到索引中间,导致索引页拆分,增加IO开销);
  • 整数型索引的存储空间更小、查询效率更高(相比字符串主键,如UUID,整数型索引的比较和存储更高效)。

反例:使用UUID、随机字符串作为主键,会导致索引碎片化严重,写入和查询性能下降。

九、避免使用NULL值过多的字段建立索引

MySQL的索引不会存储NULL值(或仅存储NULL的标记),若字段中NULL值占比过高(如超过50%),索引的过滤效果会极差,MySQL可能直接放弃使用该索引,转而执行全表扫描。

建议:对于可能存在大量NULL值的字段,可先通过默认值(如空字符串、0)处理NULL值,再考虑是否建立索引。

总结:MySQL索引设计的核心是“平衡查询效率和维护成本”,需结合业务的查询场景、写入频率、数据量,优先保证高频查询的高效性,同时避免过度索引和无效索引,让索引真正成为提升数据库性能的工具。

ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花

MySQL存储引擎与索引 文章被收录于专栏

还在纠结MySQL存储引擎怎么选?选错直接拉垮系统性能!MySQL插件式存储引擎架构适配多元业务:InnoDB(默认)支持事务、行级锁,扛高并发OLTP场景;MyISAM查询快无事务,适配读多写少场景;Memory读写极速但无持久化,适合临时缓存;Archive高压缩归档日志,CSV便捷跨系统交互,NDB支撑分布式集群。本期专栏拆解各引擎核心特性与选型逻辑,教你选对引擎,让数据库性能拉满!

全部评论
如果大家在工作学习中或者面试中遇到不会的问题可以将问题发在评论区,如果是经典的问题,我可以给出对应的文章,欢迎大家讨论
点赞 回复 分享
发布于 03-10 19:12 北京

相关推荐

【开篇】2025:我的技术成长与求职之路时间过得真快,转眼2025年就要翻篇了。站在年尾回顾,感觉这一年被填得满满当当,从年初的埋头苦学,到年末的尘埃落定,每一个节点回想起来都格外清晰。想和大家分享的,不是什么辉煌的成绩,就是一个普通技术人较为真实的一年。一月到三月:打地基开年的重心很明确,就是夯实后端开发的基础。一月,我一边动手做“苍穹外卖”项目来练手,一边啃完了操作系统和计算机网络这两大块硬骨头,还背了大量的Java八股文。现在想想,那段日子虽然单调,但那种“知道自己在进步”的感觉很踏实。三月份,为了应对天梯赛,我开始在洛谷和PTA上疯狂刷题,每天都跟算法死磕。最终以B组铜牌的成绩收尾,不算惊艳,但也是个不错的开始,这段经历让我觉得,面对反复的练习和暂时的瓶颈,坚持本身就是一种解法。三月到六月:从零到一三月的另一个重点是启动我自己的第一个完整项目:Blossom花店。这是一个Java后端项目,从设计到编码,全都自己摸索。四月初完成了第一版并上传到GitHub,之后就是持续地迭代优化。最幸运的是,后来和一位前端同学组队合作,我们一起把这个项目不断完善,并在六月完成了最终的部署上线。让项目真正跑起来的那一刻,成就感是难以言喻的。更没想到的是,这个项目后来还为我们赢得了网页设计大赛的一等奖。这段经历让我深深体会到,动手做一个完整的、能跑的项目,对能力提升的帮助远超单纯的阅读和刷题,而团队协作则能让想法走得更远。七月到九月:拥抱变化七月,我有了第一段在小厂的后端实习。就在同一时间,我的技术探索欲被点燃,开始着手第二个更具挑战的项目:“淬月智能志愿服务平台”。我尝试将当时最新的SpringAI和RAG技术用进去,搭了几个智能体和知识库,还接入了字节的Coze来进一步优化服务体验。那段时间,工作之外的所有精力几乎都扑在项目上。九月份实习结束后,我根据当时的市场观察和个人兴趣,做了一个重要的方向调整:转向测试开发。这段经历让我觉得,技术之路并非一条单行道,保持对新技术的敏感,并敢于根据现实调整航向,同样重要。十月到十二月:厚积薄发下定决心后,我用九月和十月这两个月的时间,集中火力攻关Python自动化测试脚本开发,并系统地补足了测试的基础理论知识。功夫不负有心人,十月底,我拿到了来自上海哈啰的测试开发岗Offer,这是我人生中第一份真正意义上的大厂Offer。在哈啰实习了两个多月后,一个意外的机会降临——我收到了字节跳动的面试邀请。抱着试一试的心态,我开始了准备。那段时间,每天下班后的必修课就是刷SQL、刷算法、整理公司业务文档、复盘面试八股,周末也跟朋友在星巴克狂卷。过程很辛苦,但现在回想,那段辛苦的日子,恰恰是成长最快的时候。十二月底,我成功拿下了字节的Offer。说实话,那一瞬间除了开心,更多的是一种“努力被看见”的释然。【结尾】写在最后回头看这一年,从年初对着电脑敲下第一行项目代码,到年末手机里收到心仪的Offer邮件,每一步都踩得踉跄却扎实。我学到了一个朴素的道理:技能和项目是敲门砖,而持续的学习能力和面对变化时的调整心态,才是能够走得更远的内驱力。2025年教会我的,不是如何赢,而是如何在一场场小型战役中,保持节奏,不断进化。感谢这一年来所有给予我帮助的伙伴和平台。新的旅程即将开始,希望明年此时,能有更多故事与大家分享。共勉。
双非后端失败第N人:太强了 向佬学习
点赞 评论 收藏
分享
一面 情况:通过面经:百度后台开发实习一面 - 大概40min1. 自我介绍2. 大二实习的话时间能兼顾吗3. 常见数据结构了解过吗 说一下栈和队列的区别4. 用Golang手撕一个二分查找在数组中找到目标值(第一次手撕遇到这个内心暗暗自喜觉得面试官不为难我太好了)5. Go语言学了多久6. HTTP和HTTPS的区别7. 你说你项目里面用到了gRPC 说一下RPC和HTTP的区别8. 从浏览器输入一个网址到渲染页面出来的全过程背后是怎么样的9. 接口请求是怎么打到一个后端服务的(我重点答了打到服务器之后会根据端口去区分)10. MySQL的索引是什么11. 实际开发过程中用过什么索引 讲一下12. 项目中是怎么用Redis的 用了哪些数据类型 说一下13. MySQL聚簇索引和非聚簇索引的区别14. 进程 线程 协程有什么区别15. 你对项目部署了解多少 Docker这些有用过吗16. 平时开发用的是windows系统还是linux17. 熟悉linux基本命令吗 比如查看一个文件的最后几行内容用什么命令知道吗18. 写完二分查找之后又问了我一个微信红包的场景题 怎么保证微信红包的金额尽可能随机然后每个人抢到的概率随机 怎么去设计(这个场景题我没怎么接触过 答的不是很好)19. 常见设计模式了解过吗二面情况:通过面经:百度后台开发实习二面 - 大概35min1. 自我介绍2. 你项目中用到的SingleFlight合并请求解决缓存穿透是怎么用的 说一下3. 有没有看过SingleFlight的底层实现原理?说一下4. 如果让你用Go来实现这个 你会怎么做 说一下思路5. 你提到了channel 你知道channel的底层实现原理吗 有缓冲的channel和无缓冲的channel有什么区别?6. 项目中有没有遇到什么难点?7. 说一下你的MySQL和ES的一致性是怎么做的?8. 你说到用到了Kafka去消费消息 那你怎么保证最终同步过去后MySQL和ES同步成功(我一直在答Kafka消费失败的重试机制 死信队列那些 然后面试官说他想问的是怎么确定MySQL和ES同步成功了 我说可以考虑设计一个后台脚本来定期读取MySQL和ES 然后判断是否一致)9. 手撕题目:给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。示例 1:输入:s = "1 + 1"输出:2示例 2:输入:s = " 2-1 + 2 "输出:3示例 3:输入:s = "(1+(4+5+2)-3)+(6+8)"输出:23提示:1 <= s.length <= 3 * 105s 由数字、'+'、'-'、'('、')'、和 ' ' 组成s 表示一个有效的表达式'+' 不能用作一元运算(例如, "+1" 和 "+(2 + 3)" 无效)'-' 可以用作一元运算(即 "-1" 和 "-(2 + 3)" 是有效的)输入中不存在两个连续的操作符每个数字和运行的计算将适合于一个有符号的 32位 整数后来才知道原来这个是Hot150题库上的一道 Hard 224. 基本计算器 之前没刷过 还是自己准备不足(我一开始一直想用双栈法去做 一个栈存数字一个栈存运算符 但是当时可能是看到这道题是Hot100之外的 并且面试官一直看着我有点紧张所以就有一些细节一直没写对 最后面试官告诉我想复杂了 可以更简单一点)10. 最近在学习什么后端的方向11. 有用过Linux吗 平时开发用的是Windows还是linux觉得自己二面表现得很差 应该是要挂掉我了 没想到隔天HR打电话告诉我一二面都过了 但是因为只剩下一个hc了 想要更充分了解候选人所以再约一个三面 然后这个时候官网进度那里面试环节已经是打勾了三面情况:三面后刷新官网已挂三面没有问任何技术相关的 15分钟就结束了(面试官说一二面已经问过技术了我就不问了 心里瞬间就放松了 而且三面那天还发烧了) 单纯聊天 问我一些职业规划 还有一些个人情况什么的 然后面试官还问我为什么大二就出来实习 身边大二出来实习的多不多 未来规划是什么 我说我对技术很热爱 想学到企业开发的技术锻炼更多实战经验 然后他还问我你们学校是不是就在旁边 我说我骑个车三四分钟就到了哈哈哈(其实我经常去百度大厦下面吃麦当劳) 还问了我一些职场中的问题比如给你十个任务 每个任务优先级不一样 Deadline也不一样 如果是你的话你要怎么去在有限的时间内完成这些任务  感觉是HR面不是技术面 最后还问了我多大 聊天还挺愉快的最后自己觉得应该是被横向评估挂掉了 不过还是很感谢百度给了我人生中第一次面试的机会 遇到的面试官都都挺不错的 虽然面到了三面后把我挂了还是有点浇冷水的失落感 甚至三面之前官网进度那里面试那个选项就已经是打勾了的 然后三面完突然变成灰色了 诶 继续沉淀吧
Andrew1219:
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务