一看就会的mysql索引优化(真实案例)
时间:2022-07-24
本文章向大家介绍一看就会的mysql索引优化(真实案例),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
背景
(使用的数据库:MYSQL 5.7 版本,InnoDB 引擎) 自从服务加了Skywalking后,将大部分慢接口暴露出来。于是就有了这次慢接口的优化。大概的优化过程。
- 优化前:
- 优化后:
优化步骤
1. 排查
- 通过skywalking可以清楚的看到慢接口是在哪一步比较慢。通过调用情况可以清楚的看到其链路调用情况如下图:
如果说你的服务没有接如这种情况监控服务,那我们可以使用阿里巴巴开源的Arthas来进行链路追踪(使用trace进行查看每一步方法的调用耗时)arthas官方文档
2. 记录现有情况
- 通过排查后,可以准确的定位到是SQL很慢,这个时候我们就得针对于这条SQL仔细分析,先将业务SQL拿出来(通过控制台日志进行获取),通过explain查看SQL执行计划,这个很关键了。查看是否有走索引,查看预扫描行数,执行策略等。在这里的话主要还是依靠explain各个字段给我们提供的信息。(跑的是生产库)。获取到的主要信息进行记录.
使用的索引 |
预扫描行数 |
是否回表 |
是否排序 |
执行时间 |
结论 |
---|
3. 根据情况分析原因定具体优化方案
1. 索引走错
1. - 这种情况我们呢可以查看他的索引基数通过 show index from table_name.大概看一下cardinality基数字段,大概评估一下。然后使用命令 analyze table tb_name重新计算一下。
- 因为对与mysql选择索引其中索引基数是重要条件之一
- 索引基数是通过抽样计算计算出来的,所以不一定是准确的,所以通过analyze table进行重新采样计算后就可以了。
2. - 如果说通过索引基数还没有OK的话,那就有可能是在这条语句中与可能有排序或者有创建临时表的情况,使用这个你认为扫描行数少的有可能产生。所以你可以考虑优化索引了,创建一个符合索引且不需要回表的
2. 索引区分度低
- 在这里需要注意的就是尽量少用一些状态值创建索引。为什么呢?构建好B+树你大部分值都一样,在进行查找的时候很可能就和普通链表的时间复杂度差不多了。在这里我们真的可以果断干掉。
- 还有一种就是前面半部分基本差不多,后边一部分有一些区别,这样的话我们可以采用倒叙存储,然后在使用他创建索引,并且只使用区分度大的那一部分进行存储。更或者说多存一个字段为hash 值使用hash值做索引。在进行查找的时候直接使用计算后的hash进行匹配
3. 使用了索引有回表,有排序
- 回表,就是我们通过某个索引查出来的数据不能慢走我们所需要的那些字段,他又要将收集到的ID通过主键索引进行扫描拿到对应的字段信息。那我们的解决办法就是使用覆盖索引了。创建一个符合所需字段的索引,在这里需要注意的就是已经要评估好,不能随便一个查询语句就去创建一个联合索引。还有就是符合最左匹配原则,区分度也要大。
- 有排序,也就是在explain的时候 有filesort,这个操作会进行IO操作,进行排序。所以我们创建一个联合索引拥有这个字段的。列如我们根据用户ID,查询id对应的订单按create_time排序的联合索引,其实还有一种情况就是说如果这个用户订单有几百万单那查询性能一下子就下来了,那这个时候我们可以根据业务需求进行优化,就是说限定一个时间区间 在where 语句里。
(id,create_time)
4. 我的SQL最终定的方案是改掉两个添加一个
- 改掉区分度低的索引和不遵循最左匹配原则
- 创建一个联合索引,消除file sort
- 业务逻辑的优化,将复杂SQL进行简单优化,去掉嵌套逻辑
- 结合业务逻辑加上时间区间(当前时间前一个月)。
3. 严格有效的验证
这是最重要的一步
我的验正方案:
- 通过自己对业务的理解,预估会使用的修改过的索引的语句,进行测试,在这里的话可以和生产库进行对比
- 将原来的索引使用情况已经记录下来,然后在SIT环境数据库将原来的SQL进行跑,还有(我们SIT库是从PROD有同步数据过来的,但是还是有部分数据缺失的)
- 跑SQL的时候尽量选择筛选条件是:使用索引,并且会筛不出来数据的,防止数据排在前面导致很早就命中的偶然情况。
- 然后就是测试同学随我们优化的接口进行压测。
- 就是全量回归测试。各个查询页面随便点点
- 还算幸运最后性能提高了有1000被从几十秒到不到1ms 对其他的业务接口也没有影响。
4. 索引上线
- 变更索引无非就是 删除索引,和创建索引。在这里需要注意一下就算是变更过程中有可能导致的锁表情况,在这里我们可以产看一下关于Online DDL的这个语法(https://dev.mysql.com/doc/refman/5.7/en/innodb-online-ddl-operations.html)
- 公司业务允许,我是半夜停服搞得。但是也执行了有1个小时(900万数据)
幻觉
在实际工作中有很多同学都认为加索引会影响更新效率。但是这个影响想说对于查询很慢的影响来说很是小的一个影响。
总结
- 我自己优化的一个过程
- explain的使用(https://segmentfault.com/a/1190000008131735)
- 索引出现问题的几种情况
- 严格的测试很重要(我的测试个人认为一般)
资料
- 美团的优化索引:https://tech.meituan.com/2014/06/30/mysql-index.html
- expalin的使用:https://dev.mysql.com/doc/refman/5.7/en/using-explain.html
- Online DDL 语法:https://dev.mysql.com/doc/refman/5.7/en/innodb-online-ddl-operations.html
- arthas官方文档:https://alibaba.github.io/arthas/trace.html)
- linux学习第二十三篇:shell介绍,命令历史,命令补全和别名,通配符,输入输出重定向
- Python yield关键字 和 Generator(生成器)
- linux学习第二十篇:zip压缩,tar打包以及打包压缩
- 数据结构之图
- 您需要来一份82年的代理吗?No.12
- Python 列表生成式(List Comprehensions)
- 微信小程序开发日记:重要的var that=this
- linux学习第二十六篇:正则介绍,grep,sed,awk命令
- Python 迭代(iteration)
- Python 切片(Slice)
- Python函数参数总结(位置参数、默认参数、可变参数、关键字参数和命名关键字参数)
- linux学习第二十七篇:使用w查看系统负载,vmstat,top,sar,nload命令
- Python 函数
- Python set(集合) 这一定是最全的介绍集合的博文
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- 反制面试官 | 14张原理图 | 再也不怕被问 volatile!
- Javascript之其实我觉得原型链没有难的那么夸张!
- 归纳一下:C#线程同步的几种方法
- C# 主界面的扁平化
- C# LINQ
- Oracle基本参数(DB_NAME)
- Oracle基本参数(DB_RECOVERY_FILE_DEST,DB_RECOVERY_FILE_DEST_SIZE)
- Oracle基本参数(DB_UNIQUE_NAME)
- Oracle基本参数(DB_DOMAIN)
- Oracle基本参数(INSTANCE_NUMBER)
- Oracle基本参数(LDAP_DIRECTORY_SYSAUTH)
- C#调用C++编写的DLL
- Oracle基本参数(LOG_ARCHIVE_DEST_n)
- [安装文档]Oracle 12c 单节点安装之安装前准备
- Oracle基本参数(NLS_LANGUAGE)