mysql第七话 - mysql性能优化总结

202 阅读5分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

到这篇文章,mysql基本上算是分析完了,作为一个开发人员,有一句话是肯定听不得的,你的接口为什么响应这么慢? 那这篇文章应该能很好的帮助你解决这个问题。

Mysql优化从何下手?

从开发到运维的角度应该是这样:

  • sql和索引优化
  • 表结构和存储引擎优化
  • 根据真实的项目情况选择合适的存储引擎
  • 表结构,细分,可以适当冗余
  • 架构优化
  • 缓存
  • 基于主从复制实现的读写分离
  • 分表分库
  • 操作系统,Mysql的参数配置

配置图

  • 硬件方面,CPU,内存等

作为开发人员,接下来我们来看一张图,优先从这张图上优化 xx 接下来从这张图来一步一步分析优化之路。

1 连接

服务端:

  • Mysql max_connections,默认最大连接数是151个,可相应的调整,根据服务器可调整最大10W
  • Mysql wait_timeout,回收连接的时候

客户端:

  • 使用池化技术,hikari、durid

2 缓存

  • redis,mongo等。合理使用缓存,减少数据库连接

3 慢查询日志监控

show variables like '%_query%'
  • slow_query_log,是否开启慢查询日志,默认是关闭
  • long_query_time,超过这个时间就记录到慢查询日志里面,默认10秒
  • slow_query_log_file,存储慢查询日志的路径

当前服务修改指令:set @@global.slow_query_log = 1;,服务重启后复原 永久修改需要到Mysql配置文件my.cnf中配置 查看慢查询日志:

  • 直接到服务器查询慢查询日志文件
  • 使用工具mysqldumpslow查询慢sql详细

4 执行计划 EXPLAIN/DESC

//用法explain 、 desc都可
explain select * from xxx where id=10
idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
1SIMPLExxxconstPRIMARYPRIMARY8const1100.00
  • id:执行序号
  • select_type:查询类型
  • table:表名,也可以是临时表名
  • partitions:分区表
  • type:针对单表的访问方式
  • system:非InnoDB引擎,最快的
  • const:主键,唯一索引
  • eq_ref:join了唯一索引
  • ref:非唯一索引
  • range:索引的范围查询
  • index(full index scan):根据索引全部查询
  • ALL:全表扫描
  • possible_keys:可能用到的多个索引
  • key:单个索引
  • ken_len:索引字段的字节
  • ref:筛选数据索引方式的参考
  • row:预估扫描的行数
  • filtered:存储引擎计算出的有效数据和需要扫描数据的百分比
  • Extra:额外信息
  • using index 覆盖索引
  • using where 需要过滤,没有经过索引
  • index 索引条件下推
  • using filesort 不是根据索引排序
  • using temporary 使用到临时表

sql的执行计划中的type理论上应该至少到range,否则就是需要优化的

5 高并发优化

关系型数据库存在的性能问题:

  • 表数量过大
  • sql查询复杂
  • sql查询没走索引
  • 数据库服务器性能过低

表数据过大解决方案:

阿里开发手册:单表行数超过500W或者单表数据容量超过2G InnoDB最大适合1017列 优化方案:

  • 分表分库
  • 冷热数据分离
  • 历史数据归档,例如:order order_month order_history

6 数据库的分表分库

具体案例:kafka -> 数据分片,redis-cluster ->slot数据不同的槽位,mysql -> 分片

6.1 水平拆分

数据拆分,例如根据用户ID取模计算出来的订单表

6.2 垂直拆分

表细分,例如订单表分为订单主表和明细表

6.3 策略

  • 一般都是采用取模算法,但是表扩容时需要宕机
  • hash一致性算法,顺时针找到第一个目标表存储
  • 范围分片,根据不同的特征或群体进行分片

6.4 全局唯一ID

数据库自增ID uuid,但长度长且全是字符,占用大 雪花算法,64位二进制,从第一位至41位存时间戳,10位存工作机器ID,12位序列位,一毫秒内可以获取4千多个id redis原子递增

6.5 分表分库带来的问题

分片键查询

  • 非分片键和分片键的映射关系
  • k -v 存储映射维护

实现多个库分离

  • 读写分离
  • 可读视图

数据迁移

  • 新老库双写
  • 定时任务来同步数据并做数据校验
  • 数据迁移完了,不要马上删掉,要有回滚预案

跨库查询

  • 冗余字段
  • 绑定表
  • k - v存储映射
  • 可读视图

分页排序

  • 可读视图
  • 业务做聚合,存储缓存

6.5 分库分表解决方案

添加中间件,分担单表的性能压力

  • Sharding-sphere
  • Sharding-JDBC 客服端代理
  • Sharding-Proxy 服务端代理
  • Mycat 服务端代理

7 总结

这么说吧,我觉得在服务运行保证响应快的同时还要跑的久。 作为开发人员,在这里分享几点经验:

  • 不要无脑的添加索引
  • 尽量减少非必要的关联查询,在多张大数据量表不用做分页的情况下,宁愿多次查询
  • 查询尽量走索引,长一点的sql一定要先看执行计划
  • 统计尽量做读写分离,没这个条件的尽量异步定时跑,尽量不用实时。
  • 统计表尽量单表查询,不要一条sql查询整个统计(随着数据量增大数据库压力越来越大,而且还伴随着定期优化)
  • 经常调用的数据可以维护一套到redis,减少数据库查询次数
  • 高并发数据不要直接入库,可以借助redis,Mq等中间件保证分布式锁以后再入库
  • 定期清理无用的数据
  • 定期移动历史数据(会伴随着查询的修改,一般是表数据量大,且历史久远的才会)

最重要的来了:定期重启数据库,redis已经服务,能有效的释放连接,释放内存

以上就是本章的全部内容了。

上一篇:mysql第六话 - mysql事务与锁详解 下一篇:mysql第八话 - mysql的其它懒人用法

东隅已逝,桑榆非晚