MySQL_14_查询优化

查询优化

查询优化:通过各种方案使SQL查询更高效

1)查询优化分为:逻辑优化(重写SQL)、物理优化(索引)

2)查询优化本质:降低查询语句所需的开销



查询开销指标:响应时间扫描行数返回行数

1)响应时间:排队时间和执行时间

2)扫描行数:为完成查询扫描数据行的总数

3)返回行数:真实返回数据行的总数

//尽量使返回行数接近于扫描行数,且行的访问代价并不一定相等



查询开销高的基本原因是:访问数据过多

1)重写查询:使用更优化的查询语句;

2)覆盖索引:将使用的列均设为索引,以避免回表;

3)修改表结构:修改表结构以增高查询效率(或添加辅助表);

查询流程

查询流程:客户端与MySQL服务器连接后,查询语句的执行流程

查询流程如下:

1)客户端发送查询语句请求至MySQL服务器;

2)检查是否命中缓存,命中则直接返回结果并结束查询;

3)对查询语句进行语法和语义分析,并解析成解析树并传递给预处理器优化;

4)优化器根据解析树生成优化后的执行计划,并传递给查询执行引擎;

5)查询执行引擎调用存储引擎API执行查询,并返回结果;

//MySQL 8.0之后的版本删除命中缓存查询(功能过于鸡肋)


如:MySQL服务器接收到客户端查询语句请求后的流程
在这里插入图片描述
//实际查询流程中可能并不按此线性流程执行(可能部分模块同时执行)

MySQL客户端和服务器之间通信协议为半双工

1)客户端只能用单个数据包将查询语句传递给服务器;

2)服务器用多个数据包将结果返回给客户端,且客户端必须完整接收结果

//在客户端接收结果时,MySQL会对所有查询所使用的资源上锁



MySQL客户端通过线程连接服务器,服务器每刻都处于以下状态之一:

线程状态说明
Sleep等待客户端请求
Query正在执行查询 正在将结果发送给客户端
Locked等待锁 (锁的类型由存储引擎决定)
Analyzing and statistics生成查询执行计划 (根据存储引擎统计信息)
Copying to tmp table [on disk]正在执行查询 并将结果集复制到临时表
Sorting result正在对结果集进行排序
Sending data正在传送数据 正在生成结果集 正在将结果发送给客户端

查询缓存

查询缓存(Query Cache):将查询结果缓存并在其他查询流程开始前检测

1)查询缓存会在不同客户端之间共享;

2)本质:基于对大小写敏感的哈希查找实现;

3)查询命中查询缓存会直接返回缓存,但会再检查次用户权限;

//MySQL 8.X删除查询缓存(功能过于鸡肋)


查询缓存限制(失效):

1)查询语句必须完全相同:包括注释、大小写和空格数量;

2)不能包含函数和变量:无法确定其结果;

3)不适用频繁更新的表:缓存命中率较低;


解析器

解析器(Parser):通过关键词对查询语句进行语法/语义分析以生成解析树

1)语法分析:根据MySQL语法规则检测查询语句是否合法;

2)语义分析:根据MySQL关键词分析查询语句的语法;

3)解析树:承载查询语句以便后续优化和执行


预处理器会根据解析树做进一步处理:

1)预处理器根据MySQL规则检测解析树是否合法,并进行优化;

2)预处理器再次检测用户权限;


优化器

优化器(Optimizer):根据解析树生成执行计划

1)生成执行计划的同时会优化执行语句(逻辑优化,保证成本最小)

2)优化器决定的执行计划未必是最优的(优化器存在误判)

3)优化器分为:静态优化(编译时)、动态优化(运行时)

//SHOW STATUS LIKE ‘Last_query_cost’;可查最后一次查询成本

//优化器的估计成本并不一定是实际执行成本


优化器在以下情况会误判查询成本:

1)存在缓存:优化器不考虑任何层面的缓存;

2)并发查询:优化器不考虑任何并发执行的查询;

3)乐观评估:优化器不考虑任何不受控制的操作成本

4)统计信息不准确:优化器依靠存储引擎统计信息评估各查询成本;


常用场景

(1)重定义表的关联顺序

1)场景:表的实际关联顺序并总是按照查询语句指定的顺序进行;

2)优化:优化器会选择小表作为驱动表(减少外层循环次数);


(2)外连接变为内连接

1)场景:外连接并不总是按查询语句指定的方式连接;

2)优化:优化器会尽量使用内连接代替外连接,并优化内连接顺序;


(3)简化并规范表达式

1)场景:查询语句的表达式不简化和规范时

2)优化:优化器会使用等价的简化且规范表达式替换查询语句的表达式;


(4)转化为常数

1)场景:将查询语句中部分转化为常数

2)优化:优化器检测查询语句中表达式和语句是否可转换为常数;


(5)覆盖索引

1)场景:判断是否可调用覆盖索引

2)优化:优化器判断当前查询语句的列是否被索引列包含;


(6)转化子查询

1)场景:子查询并不总按照子查询方式进行

2)优化:优化器常使用等价的关联查询替代子查询

//子查询使用临时表存储数据,但临时表无法创建/使用索引(成本高)


(7)提前终止查询

1)场景:查询能提前终止

2)优化:优化器发现满足查询语句需求时,可立刻终止查询


(8)等值传播

1)场景:关联查询时列可互相获得对方WHERE条件

2)优化:优化器在等值关联时,将列的WHERE条件传递给其他列


HINT

优化器提示(HINT):控制优化器是否启用部分功能

(1)HIGH_PRIORITYLOW_PRIORITY

1)功能:指定语句的优先级(仅对使用表锁的存储引擎)

2)可用于SELECT、INSERT、UPDATE和DELETE语句


(2)DELAYED

1)功能:结果立刻返回客户端,将插入放入缓冲区(表空闲时再插入)

2)可用于INSERT和REPLACE语句

//会导致LAST_INSERT_ID()函数失效


(3)STRAIGHT_JOIN

1)功能1:查询语句中表只按照指定顺序关联(用于SELECT)

2)功能2:表的关联顺序不用被优化(用于JOIN)

3)可用于:SELECT和JOIN语句


(4)SQL_SMALL_RESULT和SQL_BIG_RESULT

1)功能:告知优化器是否将结果集放在内存的临时表中

2)可用于SELECT语句


(5)SQL_BUFFER_RESULT

1)功能:将结果集放入到内存的临时中再返回至客户端(尽快释放锁)

2)可用于SELECT语句


(6)SQL_CACHE和SQL_NO_CACHE

1)功能:是否将结果存储至查询缓存

2)可用于SELECT语句


(7)SQL_CALC_FOUND_ROWS

1)功能:使结果集尽可能包含更多的信息

2)可用于SELECT语句


(8)IGNORE INDEX和FORCE INDEX

1)功能:强制使用/不适用索引

2)可用于FROM语句


性能分析

EXPLAIN

EXPLAIN:分析指定语句以返回其执行计划

1)仅模拟执行指定语句,并非实际执行;

2)EXPLAIN不考虑缓存、优化器、触发器和存储过程的存在;


EXPLAIN分析格式:EXPLAIN 执行语句\G

1)也可使用“;”作为结束符,但\G增加可读性;

2)可在EXPLAIN后指定“FROMAT=JSON”获取更多信息;


分析返回的分析数据字段含义如下:

字段含义
id执行语句的唯一ID
select_type查询类型
table作用于的表名
partitions匹配的分区信息
type针对单表的访问方法
possible_keys可能使用的索引
key实际使用的索引
key_len实际使用的索引长度
ref与索引进行等值匹配的对象信息
rows估计读取的记录条数
filtered条件过滤剩余数据的百分比
Extra额外信息

(1)id:执行语句的唯一ID

1)若id相同则为同组,且执行顺序从上往下;

2)不同组中,id值越大其执行越优先;

//id应尽量少,代替其执行次数少


(2)select_type:查询类型

查询类型说明
SIMPLE简单查询 (未使用UNION)
PRIMARY外层查询
UNION RESULT结果集用于联结
UNIONUNION的结果集
DEPENDENT UNION依赖其他查询的延迟查询
UNCACHEABLE UNION延迟查询且不缓存
SUBQUERY子查询中首查询
DEPENDENT SUBQUERY子查询中延迟查询 (依赖于其他查询)
UNCACHEABLE SUBQUERY子查询且不缓存
DERIVED临时表查询
MATERIALIZEDIN条件的子查询

(3)table/type:作用于的表明、针对单表的访问方法

1)无论执行语句中包含多少表,其最终都为对单表的访问;

2)访问方法有以下12种(性能依次降低):

访问方法含义
system系统数据 (常通过内存获取)
const常量数据
eq_ref主键或非空唯一索引等值扫描
ref非主键且非唯一的等值扫描
fulltext全文索引扫描
ref_or_null主键或唯一索引等值扫描
index_merge合并索引扫描
unique_subquery唯一索引子查询
index_subquery索引子查询
range范围扫描
index索引树扫描
ALL全表扫描

(4)Extra:额外信息

额外信息说明
Using filesort数据进行文件排序(FileSort)
Using temporary使用临时表存储中间结果
Using where使用WHERE过滤数据
Using index使用覆盖索引
Using index condition部分数据命中索引进行IPC
NOT EXISTSNOT EXISTS替代IS NULL
Zero limitLIMIT 0时
Using join buffer(Block Nested Loop)子或关联查询时使用缓存优化

PROFILE

PROFILE:将MySQL上所有的执行语句相关信息记录到临时表

1)临时表按照执行顺序排序存储各个执行语句;



1)开启PROFILE记录(默认关闭):SET profiling='ON';

//可查询该变量验证是否开启


2)查看PROFILE记录:SHOW profiles;

//默认仅返回所有执行语句的总开销


3)查看最近一次查询的各个阶段的开销:SHOW profile 资源;


资源说明
ALL全部显示
CPU仅显示CPU相关
IPC仅显示接收/发送数据
SWAPS仅限交换次数
MEMORY仅显示内存
BLOCK IO仅显示IO
PAGE FAULTS仅显示页面错误
CONTEXT SWITCHES仅显示上下文切换

//若省略资源,则仅显示各个阶段的总开销

//可在最后添加“FOR QUERY 数值N”以显示多个查询开销


慢查询

慢查询:将执行超过指定时间的操作记录到日志文件

1)慢查询日志的开销可忽略不计,但长期开启需部署日志轮转工具;


常用命令如下:

1)开启慢查询(默认关闭,临时)

SET GLOBAL slow_query_log='ON';

//也可通过修改配置文件slow_query_log实现永久开启


2)指定慢查询限定时间为N秒(可为小数)

SET GLOBAL long_query_time=数值N

//查看该变量可得知慢查询限定时间(默认10秒)


3)指定慢查询日志文件路径

SET GLOBAL long_query_time=数值N

//查看该变量可得知慢查询日志文件路径


4)返回已记录慢查询总数

SHOW STATUS LIKE 'slow_queries';


5)记录未使用索引的查询

SET GLOBAL log_queries_not_using_indexes='ON';



mysqldumpslow命令:分支慢查询日志文件

指令格式:mysqldumpslow 选项 慢查询日志文件路径

选项含义
-s以指定方式排序慢查询
-t N返回前N条慢查询
-g 正则表达式正则表达式匹配含特定关键词的慢查询

-s选项有以下种排序方式:

排序方式说明
c访问次数
l锁定时间
r返回记录
t查询时间
al平均锁定时间
ar平均返回记录数
at平均查询时间 (默认方式)
ac平均查询次数

优化方案

关联优化

关联查询的执行流程:

1)先在一个表中循环取出单条数据;

2)使用该单条数据到下个表中寻找匹配的数据行(嵌套循环执行该步骤);

3)根据各个表匹配的数据行,返回查询语句中所需的列;

4)在最后一个表中找所有匹配的数据行(找到则结束);

5)依次返回上层表尝试找到更多匹配的数据行;



尽量避免使用关联查询,单表查询获取结果集后在应用层中再进行关联

1)高扩展:更易对数据库做拆分

2)查询效率高:单表查询效率远高于关联查询

3)减少锁竞争:单表查询对锁的持有时间很短;

4)缓存效率高:避免部分表发生更新时缓存的失效;

5)减少冗余查询:应用层再关联可避免重复访问数据;

6)易实现哈希关联:避免使用MySQL的嵌套循环关联;



关联查询优化方案:

(1)左外连接时应选择小表作为驱动表,大表作为被驱动表

1)原因:减少外层循环次数

2)MySQL底层将所有右外连接改为等价的左外连接执行


(2)内连接时会自动将小结果集的表选为驱动表

1)原因:减少外层循环次数


(3)用含索引的字段作为连接字段

1)原因:保证数据检索时可使用索引

2)常在关联顺序中的第二个表的列上创建索引


(4)GROUP BY和ORDER BY语句只涉及一个表中的列

1)原因:保证可使用索引

排序优化

尽量避免进行排序(或避免对大量数据进行排序)

1)大量数据排序常会导致索引失效,只能进行FileSort

2)常需排序的数据可使用索引进行存储


FileSort:在磁盘中对数据进行排序

1)FileSort的排序方式分为:双路排序、单路排序

2)MySQL默认的排序方式为内存排序(只能用于小数据)


双路排序(慢):随机IO(两次IO)

1)扫描磁盘获取指针和ORDER BY列,并进行排序

2)根据排序结果集再次扫描磁盘获取数据


单路排序(快):顺序IO(一次IO)

1)从磁盘中读取所有列到内存中

2)根据ORDER BY列进行排序,依次输出数据;



排序优化方案:

(1)使用索引排序

1)避免WHERE语句使用全表扫描

2)避免ORDER BY语句使用FileSort排序

3)无法使用索引排序时,也需对FileSort调优

//提高sort_buffer_size和max_length_for_sort_data


(2)WHERE和ORDER BY使用的列相同时

1)使用单列索引(反之,多列索引)


(3)关联查询排序时避免ORDER BY语句的列全部来自第一个表

1)全部来自第一个表时,会在处理第一个表就进行FileSort

2)默认关联结果存储至临时表中,最后进行FileSort

//关联查询进行排序时无法使用索引排序(关联结果在临时表中)


其他优化

(1)查询仅返回需要的列

1)原因:避免返回全部列(无法使用覆盖索引)

2)强烈建议禁止SELECT *


(2)将重复查询的数据添加至缓存

1)原因:避免重复多次进行相同查询流程


(3)选择WHERE而非HAVING

1)原因:WHERE效率远高于HAVING


(4)WHERE条件中使用EXISTS()代替IN()进行子查询

1)原因:每增加一个IN()条件,优化器需做的组合将以指数形式增加


(5)UNION连接需排序/过滤时,先排序/过滤再合并

1)原因:合并使用的临时表无法使用索引(效率低)


(6)尽量使用UNION ALL进行关联

1)原因:对临时表做唯一性限制的代价过高


(7)GROUP BY语句避免WITH ROLLUP进行汇总

1)原因:导致使用FileSort或临时表(无法使用索引优化)

2)尽可能在应用层使用对结果集的汇总


(8)常用LIMIT语句限制返回数据

1)避免返回数据中过多无用数据和减少扫描的数据行


(9)关联查询代替子查询

1)原因:子查询使用临时表存储数据,但临时表无法创建/使用索引

//子查询可完成逻辑尚多个步骤的操作,但效率较低(避免使用)


(10)返回结果中只有一个表中的列时才使用关联子查询

1)原因:关联子查询的成本较高,只在特殊情况下使用;


(11)将大的DELETE语句切分成多个较小的

1)原因:尽可能较小地影响MySQL性能,同时减少MySQL复制的延迟

//且每次删除后暂停段时间(减少删除时锁的持有时间)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值