MySQL性能调优如何回答不再显得是CV牛马

一、前言

今天下午吃下午茶,闲的无聊撩了下群友,问他如何MySQL性能优化知道哪些?

群友秒回:存储换性能、大字段拆分、查询优化、分区分表、读写分离。

一看这回复就是资深牛马了,对于常规的优化方式那是手拿把掐,当然仅仅只知道这些对于要成为架构师的南银还是不够的。下面我们直接上干货,简单来说MySQL性能调优分为几个方面,建表层面、sql层面、业务优化、读写分离&分库分表、硬件调整等等

二、MySQL性能调优

我们根据事务的常规发展顺序,从建表开始到硬件调整,逐一给大家讲解

2.1 建表层面

1.尽量选择较短的数据类型,尽量选择定长的数据类型

如:char 代替 varchar,固定长度处理速度更快

2.使用 not null 和 enum

如:省份、性别,可以使用 Tinyint 和 enum类型

3.使用索引

请注意甄别:哪些字段适合使用索引、是否使用联合索引

4.冗余字段

减少跨表查询,订单表里存储商品名称,而不用每次用商品id查询

5.派生列

减少每次查询的时候计算,比如用户总订单数,每次生成/取消订单的时候去计算,避免每次查询都消耗性能

2.2 sql层面

大多数CV工程师对这块很熟悉了,索引是否命中分很多场景

2.2.1 操作索引的操作符有

=, >, <, >=, <-, between, in, _, like

2.2.2 sql失效场景

  • 查询条件使用函数
  • 联合索引不符合最左匹配原则
  • 查询条件使用not in 或 <>
  • like通配符在左
  • 查询语句用or
  • 查询条件使用 is null 或 is not null
  • 查询条件使用between 或 in,且查询范围较大,查询优化器觉得全表扫描更高效

2.3 执行效率分析

比较常用的 explain 语句, procedure analyse() 语句

2.3.1 explain 语句

语法: expalin sql,如:explain select * from students;

分析结果的含义:

  • id:查询的序列号,表示查询的顺序,对于简单的查询,id通常为1,对于复杂的查询(如包含子查询或联合查询),id可能有多个值(联合查询explain后会返回多列数据)
  • select_type:表示查询的类型
    • simple:简单查询,不包含子查询或联合查询
    • primary:最外层的查询
    • subquery:子查询中的第一个select
    • derived:派生表(from子句中的子查询)
    • union:联合查询中的第二个或后续的select
    • union result:联合查询的结果
  • table:当前步骤涉及的表名;
  • partitions:涉及的分区(如果表被分区)
  • type:连接的类型,效率逐渐变高
    • ALL:全表扫描
    • index:全索引扫描
    • ranage:范围扫描
    • ref:非唯一索引扫描
    • eq_ref:唯一索引扫描
    • const:常量值
    • system:系统表(只有一行数据)
  • possible_key:查询可以利用的索引名;
  • key:实际使用的索引;
  • key_len:索引中被使用部分的长度(字节);
  • ref:显示列名字或者"const"(不明白什么意思);
  • rows:现实MySQL认为在找到正确结果之前必须扫描的行数;
  • extra:MySQL的建议;

2.3.2 analyse() 语句

语法如下:

sql 复制代码
sql procedure analyse([max_elements [,max_memory])
  • max_elements:指定每列非重复值的最大值,默认值为 256。当超过这个值时,MySQL 不会推荐 ENUM类型。
  • max_memory:为每列找出所有非重复值时可能分配的最大内存数量,默认值为 8192 字节。
  • Field_name:字段名称。
  • Min_value:该字段的最小值。
  • Max_value:该字段的最大值。
  • Min_length:该字段值的最小长度。
  • Max_length:该字段值的最大长度。
  • Empties_or_zeros:该字段为空或零的值的数量。
  • Nulls :该字段为 NULL 的值的数量。
  • Avg_value_or_avg_length:该字段的平均值或平均长度。
  • Std:该字段的标准差。

注意:此工具在MySQL8.0下架,原因是认为没人使用

移除声明:dev.mysql.com/worklog/tas...

2.4 业务优化

需要根据具体来处理

2.5 读写分离&分库分表

一般来讲,读写分离需要业务做的较大才有用,否则就是大炮打蚊子,下面我给出一个电商的案例

一个电商项目,有商品、库存、订单、购物车、支付,甚至是用户画像等内容,用户从零到千万级别,日增数据亿级,那么用单一的数据库就无法保证正常使用了,MySQL的CPU和IO占用可达到90%以上,slow sql概率大大提高,此时需要做读写分离,由于数据库功能分解,商城的主要压力来自于读,从库可水平扩展,所以暂时缓解了MySQL的压力。但是随着数据量变大,MySQL主从同步变得十分频繁,甚至出现我下单之后查不到的情况,这是read-after-write问题,master还没同步数据到slave数据库,可以根据show slave status查看,Seconds_Behind_Master值,代表主从同步从库落后主库的时间,单位为秒,若主从无延迟,则为0,如何处理主从延迟?比如增大innodb_buffer_pool_size,使用物理机,使用SSD磁盘,升级高版本MySQL,支持并行主从复制。

读写分离解决了读压力,每次读压力增加,可以通过加从库的方式水平扩展,但是写操作的压力会随着业务爆发式增长没有得到有效缓解,发现一次普通的insert操作,甚至长达一秒以上。此时,Master数据库成为性能瓶颈,那么我们再次将主库根据业务做垂直拆分,每个系统进访问对应业务的数据库,尽量避免或减少垮裤访问。垂直分库过程,也有不少挑战,最大的挑战是:不能跨库join,同时需要对现有代码重构。

读写分离,解决了读压力。垂直分库通过按业务拆分主库,缓存了写压力,但系统依然存在隐患:如单表数据量越来越大, 订单表过亿,超出MySQL极限,影响读写性能。此时需要对MySQL进一步水平拆分,问题是,根据什么逻辑拆分?第一种是根据城市拆分,另一种是根据ID拆分,按城市拆分聚合查询简单,但是数据分布不均匀,有的热点城市数据量极大,冷门城市数据很少。根据id拆分则出现跨库数据难聚合的情况,最终采取根据id拆分,从架构上,将系统分为三层:应用层,数据访问层:统一的数据访问接口,屏蔽读写分库、分表、缓存等技术细节,数据层:对DB数据进行分片,并可动态的shard分片

2.6 硬件调整

1.在机器上装更多的内存;

2.增加更快的硬盘以减少I/O等待时间;

寻道时间是决定性能的主要因素,逐字地移动磁头是最慢的,一旦磁头定位,从磁道读则很快;

3.在不同的物理硬盘设备上重新分配磁盘活动;

三、总结

想弄懂MySQL性能调优能从哪些方面下手,首先得理清sql执行链路,以及涉及的模块,平时在工作中经验经验,在学习中好好总结。
再次提醒:MySQL5.7和MySQL8.0有非常大的改动,注意项目MySQL服务使用版本

详情请查看以下链接:

相关推荐
xin-cyy4 小时前
MySQL的索引和事务
数据库·mysql
一眼青苔7 小时前
如何在MySQL中实现类似Redis的PING命令的功能来检测连接状态?
数据库·redis·mysql
hweiyu008 小时前
MySQL性能分析工具:SHOW PROCESSLIST
数据库·mysql
may_一一11 小时前
Docker中mysql镜像保存与导入
mysql·docker·容器
Pasregret11 小时前
云原生 MySQL 架构:从容器化到 Serverless
mysql·云原生·架构
Pasregret12 小时前
MySQL 安全架构:从渗透测试到合规审计
数据库·mysql·安全架构
为美好的生活献上中指12 小时前
java每日精进 5.07【框架之数据权限】
java·开发语言·mysql·spring·spring cloud·数据权限
阿文弟13 小时前
MYSQL之索引结构,为何要用B+树
数据库·mysql
博睿谷IT99_13 小时前
MySQL OCP 认证限时免费活动 7 月 31 日 前截止!!!
数据库·mysql·开闭原则