MySQL|熬夜冠军,硬肝三天,最全MySQL性能优化整理完成,不收藏会后悔

文章图片

文章图片

文章图片

文章图片

文章图片

文章图片

文章图片

MySQL“被动”性能优化汇总!年少不知优化苦 , 遇坑方知优化难 。——村口王大爷
本文内容导图如下:
既然都说了性能优化的内容 , 那性能优化就应该一把梭子吗?还是要符合一些规范和原则呢?
所以 , 在开始之前(MySQL 优化) , 咱们先来聊聊性能优化的一些原则 。
性能优化原则和分类性能优化一般可以分为:
- 主动优化
- 被动优化
而被动优化刚好与主动优化相反 , 它是指在发现了服务器卡顿、服务异常或者物理指标异常的情况下 , 才去优化的这种行为 。
性能优化原则无论是主动优化还是被动优化都要符合以下性能优化的原则:
- 优化不能改变服务运行的逻辑 , 要保证服务的正确性;
- 优化的过程和结果都要保证服务的安全性;
- 要保证服务的稳定性 , 不能为了追求性能牺牲程序的稳定性 。 比如不能为了提高 Redis 的运行速度 , 而关闭持久化的功能 , 因为这样在 Redis 服务器重启或者掉电之后会丢失存储的数据 。
以上原则看似都是些废话 , 但却给了我们一个启发 , 那就是我们性能优化手段应该是:预防性能问题为主+被动优化为辅 。
也就是说 , 我们应该以预防性能问题为主 , 在开发阶段尽可能的规避性能问题 , 而在正常情况下 , 应尽量避免主动优化 , 以防止未知的风险(除非是为了 KPI , 或者是闲的没事) , 尤其对生产环境而言更是如此 , 最后才是考虑被动优化 。
PS:当遇到性能缓慢下降、或硬件指标缓慢增加的情况 , 如今天内存的占用率是 50% , 明天是 70% , 后天是 90%, 并且丝毫没有收回的迹象时 , 我们应该提早发现并处理此类问题(这种情况也属于被动优化的一种) 。MySQL 被动性能优化所以我们本文会重点介绍 MySQL 被动性能优化的知识 , 根据被动性能优化的知识 , 你就可以得到预防性能问题发生的一些方法 , 从而规避 MySQL 的性能问题 。
本文我们会从问题入手 , 然后考虑这个问题产生的原因以及相应的优化方案 。 我们在实际开发中 , 通常会遇到以下 3 个问题:
- 单条 SQL 运行慢;
- 部分 SQL 运行慢;
- 整个 SQL 运行慢 。
问题 1:单条 SQL 运行慢问题分析造成单条 SQL 运行比较慢的常见原因有以下两个:
- 未正常创建或使用索引;
- 表中数据量太大 。
如果表的索引已经创建了 , 接下来就要检查一下此 SQL 语句是否正常触发了索引查询 , 如果发生以下情况那么 MySQL 将不能正常的使用索引:
- 在 where 子句中使用 != 或者 <> 操作符 , 查询引用会放弃索引而进行全表扫描;
- 不能使用前导模糊查询 , 也就是 '%XX' 或 '%XX%' , 由于前导模糊不能利用索引的顺序 , 必须一个个去找 , 看是否满足条件 , 这样会导致全索引扫描或者全表扫描;
- 如果条件中有 or 即使其中有条件带索引也不会正常使用索引 , 要想使用 or 又想让索引生效 , 只能将 or 条件中的每个列都加上索引才能正常使用;
- 在 where 子句中对字段进行表达式操作 。
- 尽量使用主键查询 , 而非其他索引 , 因为主键查询不会触发回表查询;
- 查询语句尽可能简单 , 大语句拆小语句 , 减少锁时间;
- 尽量使用数字型字段 , 若只含数值信息的字段尽量不要设计为字符型;
- 用 exists 替代 in 查询;
- 避免在索引列上使用 is null 和 is not null 。
回表查询:普通索引查询到主键索引后 , 回到主键索引树搜索的过程 , 我们称为回表查询 。解决方案 2:数据拆分当表中数据量太大时 SQL 的查询会比较慢 , 你可以考虑拆分表 , 让每张表的数据量变小 , 从而提高查询效率 。
1.垂直拆分指的是将表进行拆分 , 把一张列比较多的表拆分为多张表 。 比如 , 用户表中一些字段经常被访问 , 将这些字段放在一张表中 , 另外一些不常用的字段放在另一张表中 , 插入数据时 , 使用事务确保两张表的数据一致性 。 垂直拆分的原则:
- 把不常用的字段单独放在一张表;
- 把 text , blob 等大字段拆分出来放在附表中;
- 经常组合查询的列放在一张表中 。
表的其他优化方案:
- 使用可以存下数据最小的数据类型;
- 使用简单的数据类型 , int 要比 varchar 类型在 MySQL 处理简单;
- 尽量使用 tinyint、smallint、mediumint 作为整数类型而非 int;
- 尽可能使用 not null 定义字段 , 因为 null 占用 4 字节空间;
- 尽量少用 text 类型 , 非用不可时最好考虑分表;
- 尽量使用 timestamp , 而非 datetime;
- 单表不要有太多字段 , 建议在 20 个字段以内 。
解决方案:慢查询分析MySQL 中自带了慢查询日志的功能 , 开启它就可以用来记录在 MySQL 中响应时间超过阀值的语句 , 具体指运行时间超过 long_query_time 值的 SQL , 则会被记录到慢查询日志中 。 long_query_time 的默认值为 10 , 意思是运行 10S 以上的语句 。 默认情况下 , MySQL 数据库并不启动慢查询日志 , 需要我们手动来设置这个参数 , 如果不是调优需要的话 , 一般不建议启动该参数 , 因为开启慢查询日志会给 MySQL 服务器带来一定的性能影响 。 慢查询日志支持将日志记录写入文件 , 也支持将日志记录写入数据库表 。 使用 mysql> show variables like '%slow_query_log%'; 来查询慢查询日志是否开启 , 执行效果如下图所示:
slow_query_log 的值为 OFF 时 , 表示未开启慢查询日志 。
开启慢查询日志开启慢查询日志 , 可以使用如下 MySQL 命令:
mysql> set global slow_query_log=1不过这种设置方式 , 只对当前数据库生效 , 如果 MySQL 重启也会失效 , 如果要永久生效 , 就必须修改 MySQL 的配置文件 my.cnf , 配置如下:
slow_query_log =1slow_query_log_file=/tmp/mysql_slow.log当你开启慢查询日志之后 , 所有的慢查询 SQL 都会被记录在 slow_query_log_file 参数配置的文件内 , 默认是 /tmp/mysql_slow.log 文件 , 此时我们就可以打开日志查询到所有慢 SQL 进行逐个优化 。
问题 3:整个 SQL 运行慢问题分析当出现整个 SQL 都运行比较慢就说明目前数据库的承载能力已经到了峰值 , 因此我们需要使用一些数据库的扩展手段来缓解 MySQL 服务器了 。
解决方案:读写分离一般情况下对数据库而言都是“读多写少” , 换言之 , 数据库的压力多数是因为大量的读取数据的操作造成的 , 我们可以采用数据库集群的方案 , 使用一个库作为主库 , 负责写入数据;其他库为从库 , 负责读取数据 。 这样可以缓解对数据库的访问压力 。
MySQL 常见的读写分离方案有以下两种:
1.应用层解决方案可以通过应用层对数据源做路由来实现读写分离 , 比如 , 使用 SpringMVC + MyBatis , 可以将 SQL 路由交给 Spring , 通过 AOP 或者 Annotation 由代码显示的控制数据源 。 优点:路由策略的扩展性和可控性较强 。 缺点:需要在 Spring 中添加耦合控制代码 。
2.中间件解决方案通过 MySQL 的中间件做主从集群 , 比如:Mysql Proxy、Amoeba、Atlas 等中间件都能符合需求 。 优点:与应用层解耦 。 缺点:增加一个服务维护的风险点 , 性能及稳定性待测试 , 需要支持代码强制主从和事务 。
扩展知识:SQL 语句分析在 MySQL 中我们可以使用 explain 命令来分析 SQL 的执行情况 , 比如:
explain select * from t where id=5;如下图所示:
其中:
- id — 选择标识符 , id 越大优先级越高 , 越先被执行;
- select_type — 表示查询的类型;
- table — 输出结果集的表;
- partitions — 匹配的分区;
- type — 表示表的连接类型;
- possible_keys — 表示查询时 , 可能使用的索引;
- key — 表示实际使用的索引;
- key_len — 索引字段的长度;
- ref— 列与索引的比较;
- rows — 大概估算的行数;
- filtered — 按表条件过滤的行百分比;
- Extra — 执行情况的描述和说明 。
- all — 扫描全表数据;
- index — 遍历索引;
- range — 索引范围查找;
- index_subquery — 在子查询中使用 ref;
- unique_subquery — 在子查询中使用 eq_ref;
- ref_or_null — 对 null 进行索引的优化的 ref;
- fulltext — 使用全文索引;
- ref — 使用非唯一索引查找数据;
- eq_ref — 在 join 查询中使用主键或唯一索引关联;
- const — 将一个主键放置到 where 后面作为条件查询 ,MySQL 优化器就能把这次查询优化转化为一个常量 , 如何转化以及何时转化 , 这个取决于优化器 , 这个比 eq_ref 效率高一点 。
- 单条 SQL 运行慢;
- 部分 SQL 运行慢;
- 整个 SQL 运行慢 。
图片整体展开相当大 , 这里就不展开看了 , 只展示一部分 , 需要这份导图的 , 关注+转发后 , 私信“资料”即可查看获取方式
书中自有黄金屋 , 书中自有颜如玉 , 上面这张图的编写 , 我也不是单独完成的 , 也参考了下面的这份文档资料 , 这里也分享给大家 , 希望能对大家有所帮助
需要这份文档以及这张知识图谱的 , 关注+转发后 , 私信“资料”即可基础篇
性能优化篇
架构设计篇
【MySQL|熬夜冠军,硬肝三天,最全MySQL性能优化整理完成,不收藏会后悔】需要这份文档以及这张知识图谱的 , 关注+转发后 , 私信“资料”即可
推荐阅读
- 纪录之夜!国米750万锋霸10连杀,决赛国米占优,冠军即将到来
- 春晚|《星光大道》最惨冠军,曾是春晚压轴歌手,刚红1年沦落街头卖唱
- 今年,我想再次听到“我们是冠军”
- 小鲤鱼的歌|LGD战队“梦回S5”,直接零封IG晋级四强,“冠军皮肤选皎月”?
- 总决赛|世冠总决赛还未开打,FMVP冠军皮肤已提前锁定?喜欢曜的玩家赚大了!
- 娱乐圈再出全才,陈小纭勇夺今年射箭冠军,还有什么是她不会的?
- 黄林SEO|今年,我想再次听到“我们是冠军”
- 王者荣耀:TS世冠杯让三追四,最后一刻才知道谁是冠军,这就是电竞的魅力
- 穿越火线|CF先遣服快讯:冠军的象征!黑骑士-冠军之势抢先看!
- 王者荣耀|王者世冠总决赛:奇迹不止,TS让三追四击败DYG拿下总冠军
