MySQL 优化实战 - 索引篇

关于SQL优化,这个问题,相信大家过多过少都有过一些了解。最近我也在研究SQL优化方面的东西,分享一些经验。

首先简单介绍下索引,"索引" 是SQL优化中很重要的一部分(但是索引并不是优化的唯一选项)

索引原理简述

如何理解索引?索引其实就是一种数据结构,用于快速定位和访问数据库中的数据。

通常来说索引使用的数据结构是 B-Tree / B+Tree。以B-Tree为例,假设每个节点存储100个Key,三层的B-Tree 可存储一百万数据,如果将根节点存入内存中的话,只需要读取两次磁盘就可以从100万数据中找到指定数据

B-Tree

关于B-Tree 推荐阅读这篇 https://www.geeksforgeeks.org/introduction-of-b-tree-2/ 包含B-Tree的查询,新增,删除操作如何实现

MySQL 执行计划

SQL优化中查看执行计划是必不可少的一项,通过 explain 关键字可以查看MySQL中的执行计划

image.png

注:\G 含义是纵向显示结果

如果之前没有了解的 EXPLAIN 的同学,看到这个列表肯定是一脸懵逼。没关系我们先来挑几个重要的属性认识一下。

  • type:ALL 代表全表扫描
  • key:代表使用的索引,NULL 代表没有使用索引
  • rows:扫描行数

关于explain 再扩展一下,先执行 explain extended ...; ,再执行 SHOW WARNINGS 可以看到MySQL优化器对我们的SQL做了什么优化。如下图所示

image.png

利用索引来优化SQL

使用索引的优点:减少服务器扫描的数据量、避免排序和临时表、将随机I/O变为顺序I/O

通过下图,我们可以看到,添加了索引之后扫描行数从三十万行降到了1,性能提升可想而知

image.png

生产环境要注意,创建索引是一个非常耗时的操作,并且会阻塞其他操作。

生产环境添加索引有没有什么完美方案?
有的,如果你的MySQL使用主从策略的时候,可以像Nginx不停机升级web服务那样,先移除一个节点为该节点执行 ALTER TABLE 操作,然后巴拉巴拉,因为具体我也没操作过就不细说了,感兴趣大家可以Google一下,动手尝试一下。如果是单机部署的话,只能用户少的时候在执行这种操作了

使用索引连接表

索引也可以提高表连接的性能,下面是个例子,用户表左连订单表,对user_id 添加索引的前后对比

未添加索引
添加索引
like优化
image.png

通过上述例子,我们可以看出,如果模糊查询时以%开头的话,MySQL无法使用索引,但是通常来说模糊查询时我们的匹配方式都会是 %xxx%,那么如何优化呢?

这里可以通过存"反值"的方式巧妙的解决这个问题,例如我现在在数据库加一列 reverse_order_no 存储订单号的反值(并添加索引),匹配的时候再通过 REVERSE('%910') 函数将参数取反。

image.png

这里也可以使用 or,如下图,查看执行计划会发现Extra 属性返回 "Using sort_union(order_no,reverse_order_no); Using where" 这里代表MySQL发生了索引合并,后文我们会讲到

image.png
排序以及多列索引

排序需要加索引!相信大家可能知道这个道理,但是如下图所示,user_id 和 addtime 两列都建立了索引,那么下面这条查询排序使用索引了吗?

image.png

答案是:并没有!为什么?注意 Extra 中的 using filesort,代表MySQL 使用了内部文件排序算法对结果集进行了排序。MySQL 通常在一个表上只选择一个索引(有例外的情况),这种情况如果我们希望排序使用索引的话,可以建立一个多列索引,如下图所示

image.png

而且多列索引最左边的列,可以当作单列索引来使用

MySQL 优化器特性

我们刚刚说过 MySQL 通常在一个表上只选择一个索引,如何理解?例如索引A和索引B 一个需要扫描十万行,一个需要扫描五万行,那么MySQL一定选择开销最小的索引方式。

在一些特殊情况下,MySQL 会选择 Index Merge(索引合并),即在一个表上使用多个索引

  • Union:两个基数很高的索引执行OR操作时
image.png
  • Sort-Union:与上述类似,一旦or的左右两边出现范围查询,会使用该算法,区别是Sort-Union会进行排序
image.png
  • intersect:针对唯一值不多的索引列,例如在 is_pay(0-未支付,1-支付),is_send(0-未发货,1-发货) 两列建立索引,查询已支付并且未发货的订单,如下图所示
image.png

根据MySQL 5.7开发文档所示,还有一种会使用intersect,InnoDB 主键上的任何范围搜索

image.png

关于Index Merge的更多信息,参考MySQL开发文档
https://dev.mysql.com/doc/refman/5.7/en/index-merge-optimization.html

索引的影响

添加索引虽然可以提升我们的SQL性能,但是随之而来也会带来一定的开销

  • 数据插入和更新的性能,因为需要构建索引的原因,在数据量大的时候会比较明显,下图是 《Effective MySQL之SQL语句最优化》中对添加索引前后的插入性能对比
image.png
  • 磁盘空间的影响,同样也是来自于书中的测试
image.png
image.png

可以看到在添加了索引之后,空间占用是原来的7倍,在数据量庞大时,这是一个需要关注的点。

还有需要注意的一点是,在MySQL Innodb 中有聚簇索引和二级索引,一般来说主键就是聚簇索引,而其他的索引都是二级索引。

二级索引所存储的值是聚簇索引。所以当使用二级索引来进行检索时,MySQL 会先通过该索引找到对应的聚簇索引,再通过该聚簇索引找到对应的数据。这时使用占用字节更小的类型来做主键会更好,会节省索引占用空间

参考

Effective MySQL之SQL语句最优化

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容