慢SQL优化一点小思路

时间:2024-05-06


顾名思义,运行时间较长的SQL即为慢SQL,多久算慢,如何定义?
SQL运行快慢是一个相对的概念,不同的业务场景下要求不同,慢SQL的标准也就不同。
MySQL中long_query_time参数定义了SQL运行阈值,默认为10s,可通过设置该阈值来调整基准。


参考:生产环境慢SQL一般设置为0.1~0.2s,但实际上会关注的慢sql一般>1s。

sql查询为什么会慢?我们先看一下sql的执行过程:

image.png

如上图所示,一条SQL语句执行时,分为以下几步:

  1. 若查询缓存打开则会优先查询缓存,若命中则直接直接返回结果给客户端。
  2. 若缓存未命中,此时MySQL需要搞清楚这条语句需要做什么,则通过分析器进行词法分析、语法分析。
  3. 搞清楚要做什么之后,MySQL需要通过优化器进行优化执行计划。
  4. 最后通过执行器与存储引擎提供的接口进行交互,将结果返回给客户端。

MySQL执行过程中,优化器通过成本计算预估出执行效率最高的方式,以便执行器以最高效率执行SQL。 基本的成本预估维度为:I/O成本+CPU成本。

  • I/O成本:从磁盘读取数据到内存的开销,其成本常数为1.0。
  • CPU成本:从磁盘读到数据后放到内存中处理数据的开销,其成本常数为0.2。 怎么计算成本?
  1. 根据搜索条件,找出所有可能使用的索引,也就是explain的possible_keys。
  2. 计算全表扫描的开销。
  3. 计算使用不同索引执行查询的开销。
  4. 对比各种执行方案的开销,开销最小的那一个。

全表扫描成本计算:I/O成本+CPU成本

  1. I/O成本=页数 * 1.0(成本常数) + 1.1(微调数)
  2. CPU成本=数据行数 * 0.2(成本常数) + 1.0(微调数) 使用索引查询成本计算:I/O成本+CPU成本+回表I/O成本+回表CPU成本
  3. I/O成本=扫描区间 * 1.0(成本常数)
  4. CPU成本=数据行数 * 0.2(成本常数) + 0.01(微调数)
  5. 回表I/O成本=扫描区间 * 1.0(成本常数)
  6. 回表CPU成本=数据行数 * 0.2(成本常数) 注:mysql规定,当读取索引扫描的时候,每当读取一个扫描区间或者范围区间的IO成本,和读取一个页面的IO成本,是一样的,都是1.0。

基于以上两个维度我们可以得到影响SQL执行效率的关键在于I/O开销和CPU开销。哪些因素会影响到这两点呢?大致可总结以下几点:

  1. I/O成本
    • 数据量:数据量越大需要的I/O次数越多。
    • 数据从哪读取:从缓存读取还是从磁盘读取;是否通过索引快速查找;
  2. CPU成本
    • 数据处理方式:排序、子查询等,需要先把数据取到临时表中,再对数据进行加工。

影响MySQL各种类型的活动都会被记录在日志文件当中,常见的日志文件包括:

  • 错误日志(error log):记录MySQL启动、运行、关闭时的问题。
  • 二进制日志(binlog):记录对MySQL数据库执行更改的所有操作。
  • 慢查询日志(slow query log):记录运行时间超过long_query_time阈值的所有SQL语句。
  • 查询日志(log):记录了所有对MySQL数据库请求的信息。

我们可以通过慢查询日志来查看慢SQL,默认情况下MySQL数据库不启动慢查询日志,需要手动将参数设置为:ON。

慢日志配置操作:

  1. 查看当前慢日志配置: image.png 如上图所示:
  • slow_quer_log:开关为ON,即打开状态。
  • slow_query_log_file:慢日志文件写入地址。
  • slow_query_log_always_write_time:定义了日志在查询结束后多久开始写。
  1. 开启慢日志配置:退出后重新连接即可生效。

image.png

MySQL提供了一个explain命令, 它可以对语句进行分析, 并输出执行的详细信息。


image.png 如上图所示:

列名含义
select_typeselect子句类型
partitions匹配的分区
type访问类型,即怎么找数据行的方式(ALL, index,? range, ref, eq_ref, const, system, NULL)
possible_keys能使用的索引
key预测使用的索引
key_len索引使用的字节数
ref连接匹配条件
rows估算出所查到的数据行数
filtered通过条件过滤出的行数所占百分比估计值,1~100,100表示没有做任何过滤
Extra该列包含MySQL解决查询的详细信息

通过explain命令,我们能分析出一些慢SQL的常见原因:

  • 索引使用问题,通过和两个字段查看:
    • 没有使用索引
    • 优化器选择了错误索引
    • 没有实现覆盖索引
  • I/O开销问题,通过和字段来查看:
    • 扫描的行数过多
    • 返回无用列且无用列有明显I/O性能开销(比如text、blob、json 等类型)

explain只能分析到SQL的预估执行计划,无法分析到SQL实际执行过程中的耗时,可以通过配置profiling参数来进行SQL执行分析。开启参数后,后续执行的SQL语句都会记录其资源开销,包括IO,上下文切换,CPU,Memory等等,我们可以根据这些开销进一步分析当前慢SQL的瓶颈再进一步进行优化。

  1. 查看系统变量,判断该功能是否开启 :
  2. 设置系统变量,开启开关:
  3. 执行SQL语句。
  4. 查看profiles: image.png
  5. 查看指定id的SQL语句开销详细信息: image.png
  6. 关闭开关:

我们可以通过查看SQL语句执行时每一个阶段的耗时,也可以通过命令查看完整列的执行情况。

image.png

列名含义
"Status"执行阶段
"Duration"持续时间
"CPU_user"cpu用户
"CPU_system"cpu系统
"Context_voluntary"上下文主动切换
"Context_involuntary"上下文被动切换
"Block_ops_in"阻塞的输入操作
"Block_ops_out"阻塞的输出操作
"Messages_sent"消息发出
"Messages_received"消息接收
"Page_faults_major"主分页错误
"Page_faults_minor"次分页错误
"Swaps"交换次数
"Source_function"源功能
"Source_file"源文件
"Source_line"源代码行

profile只能查看到SQL的执行耗时,但是无法看到SQL真正执行的过程信息。Optimizer Trace是一个跟踪功能,它可以跟踪执行语句的解析优化执行的全过程,可以开启该功能进行执行语句的分析。 诚如上述所说,explain只能判断出SQL预估的执行计划,预估时根据成本模型进行成本计算进而比较出理论最优执行计划,但在实际过程中,预估不代表完全正确,因此我们需要通过追踪来看到它在执行过程中的每一环是否真正准确。

  1. 查看系统变量信息:
  2. 打开optimizer trace开关:
  3. 执行要SQL语句。
  4. 查看INFORMATION_SCHEMA.OPTIMIZER_TRACE表中跟踪结果: image.png 可查看分析其执行树:
  • join_preparation:准备阶段
  • join_optimization:分析阶段
  • join_execution:执行阶段 image.png
  1. 关闭开关:

服务支持

我们珍惜您每一次在线询盘,有问必答,用专业的态度,贴心的服务。

让您真正感受到我们的与众不同 !

合作流程

网站制作流程从提出需求到网站制作报价,再到网页制作,每一步都是规范和专业的。

常见问题

提供什么是网站定制?你们的报价如何?等网站建设常见问题。

售后保障

网站制作不难,难的是一如既往的热情服务及技术支持。我们知道:做网站就是做服务,就是做售后。

平台注册入口