Fork me on GitHub

MySQL查询性能优化

目的

  • 查询优化的基本原则
  • 了解MySQL执行过程
  • 浅析MySQL优化器
  • MySQL语句优化小tips
  • 理解MySQL如何查询,明白高效和低效的原因

优化数据访问

分两步分析是否是低效的查询:

  1. 是否向数据库请求了不需要的数据?
    比如查询了过多的行,查询过多的列(select * …),以及重复的查询。

  2. Mysql是否在扫描额外的记录?
    三个指标衡量查询开销:

    • 响应时间
    • 扫描行数
    • 返回的行数

重构查询的方式

  • 一个复杂查询or多个简单查询?
  • 切分查询(比如在删改操作时,将全量语句改成批量执行)
  • 分解关联查询(把一条复杂的关联查询分解为多条简单查询,可以让缓存效率更高,减少锁竞争)

一张图看Mysql执行过程

  1. 客户端将查询发送到服务器;
  2. 服务器检查查询缓存,如果找到了,就从缓存中返回结果,否则进行下一步。
  3. 服务器解析,预处理和优化查询,生成执行计划。
  4. 执行引擎调用存储引擎API执行查询。
  5. 服务器将结果发送回客户端。

1.客户端服务端通信协议

通信协议工作机制:“抛球”游戏。任意时刻,要么是客户端发送数据,要么是服务端发送数据。一旦一端发送数据(抛球),另一端只能完整的接受消息才能响应。

所以,我们需要限制发送信息的大小。
客户端:查询语句尽量少,否则可能会抛错误异常(“MySQL server has gone away”)。

# 查看你的服务器所允许传送的最大数据
SHOW VARIABLES LIKE 'max_allowed_packet' 

服务端:当服务端开始响应客户端请求时,客户端必须完整接受整个返回结果。所以要限制查询条数,必要时查询语句用“LIMIT”限制。

通过 “SHOW [FULL] PROCESSLIST” 命令查询mysql连接时线程状态:MySQL5.7通用线程状态

2.查询缓存

如果开启了缓存,MySql会检查查询缓存,进行大小写敏感的哈希查找。如果命中,判断权限没问题后会跳过所有其他阶段直接返回。

# 查看是否开启查询
SHOW VARIABLES LIKE 'query_cache_type'; 

3.解析器

解析器通过关键字解析SQL,然后生成一颗对应的“解析树”,然后它使用MySQL语法规则验证和解析语句,比如关键字是否错误,顺序等。

4.预处理

进一步检查解析树的合法性。比如检查数据表列是否存在,名字和别名等。最后,预处理器检查权限。

5.查询优化器(重点)

优化器负责将预处理合格的语法树转化为执行计划。

MySQL使用基于成本的优化器,它将尝试预测一个查询使用某种执行计划的成本,并选择成本最小的一个。

# 查询当前会话的当前查询成本
SHOW VARIABLES LIKE 'Last_query_cost'; 

Q: 那么,MySQL是如何预测成本的呢?
A: MySQL根据一系列统计信息计算得来:每个表或页面个数,索引基数,索引和数据行的长度,索引分布情况等。评估成本不考虑缓存,假设读取任何数据需要一次磁盘I/O。

可惜MySQL优化器并不是万能的,有诸多因素会导致MySQL选择错误的执行计划,比如统计信息可能不准确,成本估算和实际成有差距等。

更多的了解查询优化器是怎么处理查询语句的,查看MySQL查询优化器

6.查询执行引擎

MySQL根据解析优化阶段生成的执行计划给出的指令逐步执行。

7.返回结果给客户端

  • 查询结果返回给客户端,即时查询不需要返回结果集给客户端,也亏返回一些这个查询信息,比如影响的行数。
  • 如果查询可以被缓存,这一阶段也会存放结果入缓存。
  • MySQL结果集返回是一个增量、逐步返回的过程。一旦处理开始产生第一条结果时,MySQL就开始逐步返回结果集了。这样的好处是,服务器无须存储太多结果而消耗太多内存,二是客户端可以第一时间获得返回结果。

总结

  • 当发现MySQL查询效率不高时,考虑两个因素:1.是否请求了不需要的数据?2.是否查询了额外的记录?
  • 对待效率不高的语句,考虑语句适当拆分成多个简单的语句。
  • MySQL执行过程,看图
-------------本文结束,感谢您的阅读-------------
贵在坚持,如果您觉得本文还不错,不妨打赏一下~
0%