【MySQL】查询优化

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 【MySQL】查询优化


1. 优化目的与目标

✓ 优化的目的是让资源发挥价值;

✓ SQL和索引是调优的关键,往往可以起到“四两拨千斤”的效果。

1.1 为什么要进行查询优化

  • ✓ 提高资源利用率
  • ✓ 避免短板效应
  • ✓ 提高系统吞吐量
  • ✓ 同时满足更多用户的在线需求

1.1 MySQL优化目标

2. 优化流程及思路

✓ 充分了解核心指标,并构建完备的监控体系,这是优化工作的前提;

✓ SQL优化的原则是减少数据访问及计算;

✓ 常用的优化方法主要是调整索引、改写SQL、干预执行计划。

2.1 调优时你需要关注哪些指标

  1. CPU 使用率

SQL 查询关键资源指标

数据扫描、显式计算

  1. IOPS

每秒 IO 请求次数

物理读写关键资源指标

  1. QPS/TPS

吞吐量

业务压力

  1. 会话数/活跃会话数

应用配置

执行效率

  1. InnoDB 逻辑读/物理读

反映整体查询效率的引擎指标

  1. 临时表

导致SQL执行效率下降的特殊行为

2.1 合理监控

知道了我们关注的指标,接下来就是定点监控,看看究竟是哪个/哪些指标影响了应用系统的性能,这样就可以定点排查问题,制定具体的优化策略与方法。

2.3 MySQL优化流程

2.4 SQL优化原则与方法

2.4.1 原则

  1. 减少访问量:

数据存取是数据库系统最核心功能,所以IO是数据库系统中最容易出现性能瓶颈,减少SQL访问IO量是SQL优化的第一步;数据块的逻辑读也是产生CPU开销的因素之一。

减少访问量的方法:创建合适的索引、减少不必访问的列、使用索引覆盖、语句改写。

  1. 减少计算操作:

计算操作进行优化也是SQL优化的重要方向。SQL中排序、分组、多表连接操作等计算操作都是CPU消耗的大户。

减少SQL计算操作的方法:排序列加入索引、适当的列冗余、SQL拆分、计算功能拆分。

2.4.2 方法

  1. 创建索引减少扫描量
  2. 调整索引减少计算量
  3. 索引覆盖(减少不必访问的列,避免回表查询)
  4. SQL改写
  5. 干预执行计划

3. 原理剖析

✓ InnoDB 的表是典型的 IOT,数据本身是 B+ tree 索引的叶节点。

3.1 B+ Tree index

3.2 InnoDB Table

3.3 索引检索过程

4. MySQL的行为

✓ 扫描二级索引可以直接获取数据,或者返回主键 id;

✓ 优化器是数据库的大脑,我们要了解优化器,并观测以及干预 MySQL 的行为。

4.1 MySQL SQL执行过程

  1. 客户提交一条语句
  2. 先在查询缓存查看是否存在对应的缓存数据,如有则直接返回(一般有的可能性极小,因此一般建议关闭查询缓存);
  3. 交给解析器处理,解析器会将提交的语句生成一个解析树;
  4. 预处理器会处理解析树,形成新的解析树,这一阶段存在一些SQL改写的过程;
  5. 改写后的解析树提交给查询优化器,查询优化器生成执行计划;
  6. 执行计划交由执行引擎调用存储引擎接口,完成执行过程,这里要注意,MySQL的Server层和Engine层是分离的。
  7. 最终的结果由执行引擎返回给客户端,如果开启查询缓存的话,则会缓存。

4.2 MySQL SQL执行顺序

(9)  SELECT
        (10) DISTINCT column,
        (6)  AGG FUNC(column or expression), ...
(1)  FROM left tab1
        (3)  JOIN right tab2
        (2)  ON tab1.column = tab2.column
(4)  WHERE constraint_expression
(5)  GROUP BY column
(7)  WITH CUBE ROLLUP
(8)  HAVING constraint_expression
(11) ORDER BY column ASC|DESC
(12) LIMIT count OFFSET count;

4.3 MySQL优化器与执行计划

4.3.1 查询优化器

  • 负责生成 SQL 语句的有效执行计划的数据库组件
  • 优化器是数据库的核心价值所在,它是数据库的“大脑”
  • 优化SQL,某种意义上就是理解优化器的行为
  • 优化的依据是执行成本(CBO)
  • 优化器工作的前提是了解数据,工作的目的是解析SQL,生成执行计划

4.3.2 查询优化器工作过程

  1. 词法分析、语法分析、语义检查;
  2. 预处理阶段(查询改写等);
  3. 查询优化阶段(可详细划分为逻辑优化、物理优化两部分);
  4. 查询优化器优化依据,来自于代价估算器估算结果(它会调用统计信息作为计算依据);
  5. 交由执行器执行。

4.3.3 查看和干预执行计划

  1. 执行计划

explain [extended] SQL_Statement

  1. 优化器开关

show variables like ‘optimizer_switch’

4.3.4 processlist

show [full] processlist
information_schema.processlist

copy to tmp table:出现在某些alter table语句的copy table操作

Copying to tmp table on disk:由于临时结果集大于tmp_table_size,正在将临时表从内存存储转为磁盘存储以此节省内存

converting HEAP to MyISAM:线程正在转换内部MEMORY临时表到磁盘MyISAM临时表

Creating sort index:正在使用内部临时表处理select查询

Sorting index:磁盘排序操作的一个过程

Sending data:正在处理SELECT查询的记录,同时正在把结果发送给客户端

Waiting for table metadata lock: 等待元数据锁

5. 常规优化策略

5.1 order by - 排序

5.1.1 order by 查询的两种情况

Using index:MySQL 直接通过索引返回有序记录,不需要额外的排序操作,操作效率较高;

Using filesort:无法只通过索引获取有序结果集,需要额外的排序,某些特殊情况下,会出现 Using temporary。

5.1.2 优化目标

尽量通过索引来避免额外的排序,减少CPU资源的消耗。

✓ where 条件和 order by 使用相同的索引

✓ order by 的顺序和索引顺序相同

✓ order by 的字段同为升序或降序

注意: 当 where 条件中的过滤字段为覆盖索引的前缀列,而 order by 字段是第二个索引列时,只有 where 条件是 const 匹配时,才可以通过索引消除排序,而 between…and 或 >?、<? 这种 range 匹配 都无法避免 filesort 操作。

5.1.3 filesort

当无法避免filesort操作时,优化思路就是让filesort的操作更快。

  • 排序算法:

两次扫描算法: 两次访问数据,第一步获取排序字段的行指针信息,在内存中排序,第二步根据行指针获取记录;

一次扫描算法: 一次性取出满足条件的所有记录,在排序区中排序后输出结果集,是采用空间换时间的方式。

注: 需要排序的字段总长度越小,越趋向于第二种扫描算法,MySQL通过 max_length_for_sort_data 参数的值来进行参考选择。

  • 优化策略:

✓ 适当调大 max_length_for_sort_data 这个参数的值,让优化器更倾向于选择第二种扫描算法;

✓ 只使用必要的字段,不要使用 select * 的写法

✓ 适当加大 sort_buffer_size 这个参数的值,避免磁盘排序的出现(线程参数,不要设置过大

5.2 Subquery - 子查询

➢ 子查询会用到临时表,需尽量避免

➢ 可以使用效率更高的 join 查询来替代

  • 优化策略:

✓ 等价改写、反嵌套

如下SQL:

select * from customer where customer_id not in (select customer_id from payment);

改写成:

select * from customer a left join payment b on a.customer_id = b.customer_id where b.customer_id is null;

5.3 limit - 分页查询

➢ 分页查询,就是将过多的结果在有限的界面上分好多页来显示;

➢ 其实质是每次查询只返回有限行,翻页一次执行一次。

  • 优化目标:

✓ 消除排序

✓ 避免扫描到大量不需要的记录

SQL场景(film_id为主键):

# 此时 MySQL 排序出前 10020 条记录后仅仅需要返回第 10001 到 10020 条记录,前 10000 条记录造成额外的代价消耗
select film_id,description from film order by title limit 10000,20;
  • 优化策略:

优化策略1:覆盖索引:

alter table film add index idx_lmtest(title,description);

✓ 记录直接从索引中获取,效率最高

✓ 仅适合查询字段较少的情况

优化策略2:SQL改写

select a.film_id,a.description from film a inner join (select film_id from film order by title limit 1000,20) b on a.film_id=b.film_id;

✓ 优化的前提是 title 字段有索引

✓ 思路是从索引中取出 20 条满足条件记录的主键值,然后回表获取记录

5.4 or/and condition - 条件查询

  • and 结果集为关键字前后过滤结果的交集
  • or 结果集为关键字前后分别查询的并集
  • and 条件可以在前一个条件过滤基础上过滤
  • or 条件被处理为 UNION,相当于两个单独条件的查询
  • 复合索引对于 or 条件相当于一个单列索引

处理策略:

✓ and 子句多个条件中拥有一个过滤性较高的索引即可

✓ or 条件前后字段均要创建索引

✓ 为最常用的 and 组合条件创建复合索引

5.5 join - 连接

5.5.1 Nested-Loop Join 算法

嵌套循环连接算法

for each row in t1 matching range {
  for each row in t2 matching reference key {
    for each row in t3 {
      if row satisfies join conditions, send to client
    } 
  } 
}

5.5.2 Hash Join Optimization

Hash Join

5.5.3 关联字段索引

✓ 每层内部循环仅获取需要关心的数据;

✓ 引申算法:Bloack Nested-Loop。

添加索引前:

添加索引后:

5.5.4 小表驱动原则

✓ 减少循环次数;

✓ 小表:返回结果集较少的表。

忽略b表的索引,使b表作为驱动表:

忽略a表的索引,使a表作为驱动表:

5.6 insert - 插入

  1. 减少交互次数
-- 如批量插入语句:
insert into test values(1,2,3);
insert into test values(4,5,6);
insert into test values(7,8,9);
...
-- 可改写为如下形式:
insert into test values(1,2,3),(4,5,6),(7,8,9) ...;
  1. 文本装载方式

通过 LOAD DATA INFILE 句式,从文本装载数据,通常比 insert 语句快 20 倍。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
关系型数据库 MySQL 数据库
MySQL索引和查询优化
MySQL索引和查询优化
35 1
|
2月前
|
SQL 缓存 关系型数据库
MySQL技能完整学习列表6、查询优化——3、查询缓存——4、SQL优化技巧
MySQL技能完整学习列表6、查询优化——3、查询缓存——4、SQL优化技巧
65 0
|
2月前
|
存储 SQL 关系型数据库
三高Mysql - Mysql索引和查询优化讲解(偏理论部分)
三高Mysql - Mysql索引和查询优化讲解(偏理论部分)
51 0
|
4月前
|
SQL 缓存 关系型数据库
MySQL调优之关联查询、子查询优化
MySQL调优之关联查询、子查询优化
323 0
|
8月前
|
存储 算法 关系型数据库
第10章 索引优化与查询优化【2.索引及调优篇】【MySQL高级】3
第10章 索引优化与查询优化【2.索引及调优篇】【MySQL高级】3
123 0
|
24天前
|
缓存 关系型数据库 MySQL
MySQL查询优化:提速查询效率的13大秘籍(合理使用索引合并、优化配置参数、使用分区优化性能、避免不必要的排序和group by操作)(下)
MySQL查询优化:提速查询效率的13大秘籍(合理使用索引合并、优化配置参数、使用分区优化性能、避免不必要的排序和group by操作)(下)
|
24天前
|
缓存 关系型数据库 MySQL
MySQL 查询优化:提速查询效率的13大秘籍(索引设计、查询优化、缓存策略、子查询优化以及定期表分析和优化)(中)
MySQL 查询优化:提速查询效率的13大秘籍(索引设计、查询优化、缓存策略、子查询优化以及定期表分析和优化)(中)
|
24天前
|
存储 关系型数据库 MySQL
MySQL 查询优化:提速查询效率的13大秘籍(避免使用SELECT *、分页查询的优化、合理使用连接、子查询的优化)(上)
MySQL 查询优化:提速查询效率的13大秘籍(避免使用SELECT *、分页查询的优化、合理使用连接、子查询的优化)(上)
|
2月前
|
存储 关系型数据库 MySQL
MySQL技能完整学习列表6、查询优化——1、EXPLAIN命令的使用——2、索引优化
MySQL技能完整学习列表6、查询优化——1、EXPLAIN命令的使用——2、索引优化
23 0
|
2月前
|
SQL 关系型数据库 MySQL
三高Mysql - Mysql索引和查询优化(偏实战部分)
三高Mysql - Mysql索引和查询优化(偏实战部分)
39 1