关于SQL优化,这个问题,相信你们过多过少都有过一些了解。最近我也在研究SQL优化方面的东西,分享一些经验。
首先简单介绍下索引,"索引" 是SQL优化中很重要的一部分(可是索引并非优化的惟一选项)html
如何理解索引?索引其实就是一种数据结构,用于快速定位和访问数据库中的数据。mysql
一般来讲索引使用的数据结构是 B-Tree / B+Tree。以B-Tree为例,假设每一个节点存储100个Key,三层的B-Tree 可存储一百万数据,若是将根节点存入内存中的话,只须要读取两次磁盘就能够从100万数据中找到指定数据web
关于B-Tree 推荐阅读这篇 https://www.geeksforgeeks.org/introduction-of-b-tree-2/ 包含B-Tree的查询,新增,删除操做如何实现算法
SQL优化中查看执行计划是必不可少的一项,经过 explain
关键字能够查看MySQL中的执行计划sql
注:G 含义是纵向显示结果
若是以前没有了解的 EXPLAIN 的同窗,看到这个列表确定是一脸懵逼。不要紧咱们先来挑几个重要的属性认识一下。数据库
关于explain
再扩展一下,先执行 explain extended ...;
,再执行 SHOW WARNINGS
能够看到MySQL优化器对咱们的SQL作了什么优化。以下图所示服务器
使用索引的优势:减小服务器扫描的数据量、避免排序和临时表、将随机I/O变为顺序I/O
经过下图,咱们能够看到,添加了索引以后扫描行数从三十万行降到了1,性能提高可想而知数据结构
生产环境要注意,建立索引是一个很是耗时的操做,而且会阻塞其余操做。生产环境添加索引有没有什么完美方案?
有的,若是你的MySQL使用主从策略的时候,能够像Nginx不停机升级web服务那样,先移除一个节点为该节点执行ALTER TABLE
操做,而后巴拉巴拉,由于具体我也没操做过就不细说了,感兴趣你们能够Google一下,动手尝试一下。若是是单机部署的话,只能用户少的时候在执行这种操做了函数
索引也能够提升表链接的性能,下面是个例子,用户表左连订单表,对user_id 添加索引的先后对比性能
经过上述例子,咱们能够看出,若是模糊查询时以%
开头的话,MySQL没法使用索引,可是一般来讲模糊查询时咱们的匹配方式都会是 %xxx%
,那么如何优化呢?
这里能够经过存"反值"的方式巧妙的解决这个问题,例如我如今在数据库加一列 reverse_order_no 存储订单号的反值(并添加索引),匹配的时候再经过 REVERSE('%910') 函数将参数取反。
这里也可使用 or,以下图,查看执行计划会发现Extra 属性返回 "Using sort_union(order_no,reverse_order_no); Using where"
这里表明MySQL发生了索引合并,后文咱们会讲到
排序须要加索引!相信你们可能知道这个道理,可是以下图所示,user_id 和 addtime 两列都创建了索引,那么下面这条查询排序使用索引了吗?
答案是:并无!为何?注意 Extra 中的 using filesort,表明MySQL 使用了内部文件排序算法对结果集进行了排序。MySQL 一般在一个表上只选择一个索引(有例外的状况),这种状况若是咱们但愿排序使用索引的话,能够创建一个多列索引,以下图所示
并且多列索引最左边的列,能够看成单列索引来使用
咱们刚刚说过 MySQL 一般在一个表上只选择一个索引,如何理解?例如索引A和索引B 一个须要扫描十万行,一个须要扫描五万行,那么MySQL必定选择开销最小的索引方式。
在一些特殊状况下,MySQL 会选择 Index Merge(索引合并),即在一个表上使用多个索引
根据MySQL 5.7开发文档所示,还有一种会使用intersect,InnoDB 主键上的任何范围搜索
关于Index Merge的更多信息,参考MySQL开发文档
https://dev.mysql.com/doc/refman/5.7/en/index-merge-optimization.html
添加索引虽然能够提高咱们的SQL性能,可是随之而来也会带来必定的开销
能够看到在添加了索引以后,空间占用是原来的7倍,在数据量庞大时,这是一个须要关注的点。
还有须要注意的一点是,在MySQL Innodb 中有聚簇索引和二级索引,通常来讲主键就是聚簇索引,而其余的索引都是二级索引。二级索引所存储的值是聚簇索引。因此当使用二级索引来进行检索时,MySQL 会先经过该索引找到对应的聚簇索引,再经过该聚簇索引找到对应的数据。这时使用占用字节更小的类型来作主键会更好,会节省索引占用空间
Effective MySQL之SQL语句最优化