MySQL-索引优化实战
针对联合索引来说,如果第一列就是用范围查询,例如大于小于这些,就会认为查询的行很多,如果不是覆盖索引,那么就不再使用这个二级索引,认为使用二级索引还要频繁的去回表查询等等,消耗更大,所以就会去全表扫描。
但是可以使用force index(索引名称)去强制使用指定的索引,但是一般不建议这么做;要相信MySQL自己的优化结果。
in和or使用时,如果后面括号里面的值不多,并且表里面的数据很多,就会走索引,否则可能不会走索引。
针对like 'xx%';这样的查询一般都会去走索引的;因为5.6版本之后引入了一个索引下推的技术;
索引下推
如果ABC三个列建立了联合索引,查询条件是 A like 'xx%' and B = '' and C = '';在5.6版本之前,会去联合索引中找到符合A列的所有主键值,去主键索引中进行回表,然后将这些数据加载到内存中,然后进行B和C条件的匹配。这样回表次数会比较多,并且返回的数据量也很大,带宽压力也大。
5.6版本之后,引擎进行了优化,在匹配符合A列的条件之后,还会在二级索引中去进一步匹配B和C这两列的查询条件,这样一来会减少最终查询的值的数量,然后就会减少回表的次数,然后也会减少返回给调用方的数据量,减少网络带宽的压力。
使用索引下推的场景一般都是对于非主键的联合索引,这样可以减少回表次数,进而减少数据量
为什么范围查找Mysql没有用索引下推优化?
因为对MySQL来说,认为一般情况下范围查询的数据量是很大的,而like模糊查询的数据量是较少的;这样就可以减少查询到的主键的数据量,减少回表次数。当然这个like使用索引下推并不是绝对的,大于小于这种范围查询不使用索引下推也不是绝对的。
trace
trace工具可以展示出来经过引擎优化之后的查询语句,但是这个功能默认是关闭的,开启会消耗性能。
常见sql深入优化
Order by与Group by优化
针对排序和分组来说,通过explain分析之后,我们主要是看extra这一列。主要有两个值,有using index和using filesort。using index是使用到了索引(这个是最佳情况),using filesort是文件排序。
- MySQL使用order by支持index和filesort两种排序,index是能使用到已有索引的,效率高;filesort无法使用到索引,效率低。
- 满足using index的情况:1.order by后面的查询严格符合联合索引的最左前缀原则;2.where条件和order by的条件完全符合最左前缀原则。
- 排序时尽量使用已有的索引列,尽量使用到索引;
- 查询能使用覆盖索引就使用覆盖索引。
using filesort文件排序原理
分为单路排序和双路排序。
单路排序:就是一次性将符合条件的数据全部加载出来,在系统的sort buffer中进行排序;用trace工具可以看到sort_mode信息里显示< sort_key, additional_fields >或者< sort_key,packed_additional_fields >。
该排序的好吃就是一次性就将数据加载出来,无需进行回表操作,但是对内存大小要求较高。
双路排序:也叫做回表排序,就是根据条件先取出来排序字段和能直接定位到行的主键值,然后在sort buffer中排序,之后要进行回表将别的要查询的值查询出来填充进去。用trace工具可以看到sort_mode信息里显示< sort_key, rowid >。
该排序的好处就是对内存压力小,但是需要进行二次回表,IO压力变大。
索引设计原则
1. 索引不是越多越好,索引多了,第一是占用空间,第二维护麻烦。
2. 代码先行,待开发功能差不多完成时,将相关表的操作全部整理出来,进行分析,而不是建表时想当然的创建索引。
3. 尽量使用联合索引,因为每次查询只能命中一个索引,所以要尽可能的让查询条件都命中索引,可以适当设计三四个左右的联合索引。
4. 尽量在区分度大的列上建立索引,最好不要在性别字段加索引,因为性别就女和男,这样区分度太小,类似全表扫描。
实战开发原则:
先过滤,再去排序。
MySQL索引相关限制:
-
MySQL对索引字段长度有限制
innodb引擎的每个索引列长度限制为767字节(bytes),所有组成索引列的长度和不能大于3072字节
myisam引擎的每个索引列长度限制为1000字节,所有组成索引列的长度和不能大于1000字节
-
varchar的最大长度是指字符长度,若数据库字符集为utf-8,则一个字符占3个bytes。因此在utf-8字符集下,innodb引擎创建的单列索引长度不能超过255个字符。
mysql版本不同而导致的索引长度限制不同
在MySQL5.5版本,引入了innodb_large_prefix,用来禁用大型前缀索引,以便与不支持大索引键前缀的早期版本的InnoDB兼容
开启innodb_large_prefix可以使单索引的长度限制达到3072字节(但是联合索引总长度限制还是3072字节),禁用时单索引的长度限制为767字节
在MySQL5.5版本与MySQL5.6版本,innodb_large_prefix是默认关闭的,在MySQL5.7及以上版本则默认开启
在MySQL8.0版本中,innodb_large_prefix已被移除
这就是我在自己机器(MySQL8.0)上可以创建1024字符(utf8字符集下表示3072字节)长的索引,而在服务器(MySQL5.5)上不行的原因
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix