mysql评审_SQL业务审核与优化

本文详细介绍了MySQL评审的重要性,包括业务审核、Schema设计和SQL语句的审核要点,强调了提前发现问题并进行优化的必要性。文章还探讨了如何在业务开发的不同阶段进行SQL审核,以及如何通过优化SQL提升性能,如分析查询执行路径、优化慢查询、避免全表扫描和优化分页查询。此外,还介绍了MySQL查询优化器的工作原理、优化策略以及慢查询日志分析技巧,提供了实用的优化建议和案例。
摘要由CSDN通过智能技术生成

审核

什么是业务审核

类似与code review

评审业务Schema和SQL设计

偏重关注性能

是业务优化的主要入口之一

审核提前发现问题,进行优化

上线后通过监控或巡检发现问题,进行优化

Schema设计审核

表和字段命名是否合规

字段类型,长度设计是否适当

表关联关系是否合理

主键,更新时间保留字段等是否符合要求

约束,默认值等配置是否恰当

了解业务,表数据量,增长模式

数据访问模式,均衡度

根据业务需求,表是否需要分区,是否有数据什么周期

SQL语句审核

SQL语句的执行频率

表上是否有合适的索引

单次执行的成本

执行模式,锁情况分析

关注事务上下文

什么时候需要审核

业务开发阶段,上线前

业务版本变更,线上更新前

新表和SQL上线

SQL查询条件变化

SQL查询频率变化

业务逻辑导致现有表数据量规模变化

业务发布流程

SQL审核需要开发与应用运维支持

充分沟通,做好必要性说明和教育工作

指定业务发布流程,嵌入DBA审核环节

积累经验,不断完善评审方法

慢查询

查询优化,索引优化,库表结构优化需要齐头并进。

慢查询两个步骤分析:

确认应用程序是否向数据库请求了大量超过需要的数据

确认mysql服务器层是否在处理大量超过需要的数据记录

是否向数据库请求了不需要的数据

典型案例:

查询不需要的记录

多表关联时返回全部列

总是取出全部列

重复查询相同的数据

mysql是否在扫描额外的记录

在确定查询只返回需要的数据后,接下来应该看看查询为了返回结果是否扫描了过多的数据。

mysql查询开销的三个指标:

响应时间

扫描的行数

返回的行数

这三个指标都会记录到mysql的慢日志中,索引检查慢日志记录是找出扫描行数过多的查询的好办。

响应时间:执行时间和等待时间;

判断一个响应时间是否是合理的值,可以使用"快速上限估计"。

扫描的行数和返回的行数

分析查询时,查看该查询扫描的行数是非常有帮助的。它一定程度上说明该查询找到需要的数据的效率高不高。

如果发现查询需要扫描大量的数据但只返回少数的行,优化方法:

使用索引覆盖扫描,把所有需要用的列都放到索引中。

改变库表结构。例如使用单独的汇总表

重写这个复杂的查询,让mysql优化器能够以更优化的方式执行这个查询。

有的时候将大查询分解为多个小查询是有必要的。

查询执行的基础

mysql查询执行路径

1fef42b3098bd696875f926e7065e926.png

5697229.html

客服端发送一条查询给服务器

服务器先检查缓存。如果命中缓存,则立刻返回结果。否则进入下一阶段。

服务器端进行SQL解析,预处理,再由优化器生成对应的执行计划。

mysql根据优化器生成的执行计划,调用存储引擎的API来执行查询。

将结果返回给客户端

mysql客户端/服务器通信协议

mysql客户端和服务器之间的通信协议是"半双工"。任何时候只能一方发;不能同时发送;

mysql连接时线程状态

mysql> show fullprocesslist;+----+------+-----------+--------+---------+------+-------+------------------------+

| Id | User | Host | db | Command | Time | State | Info |

+----+------+-----------+--------+---------+------+-------+------------------------+

| 39 | root | localhost | sakila | Sleep | 4 | | NULL |

| 40 | root | localhost | sakila | Query | 0 | NULL | show full processlist |

+----+------+-----------+--------+---------+------+-------+------------------------+

2 rows in set (0.00 sec)

查询优化器

一条查询可以有很多种执行方式,最后都返回相同的结果。

优化器的作用就是找到这其中最好的执行计划。

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

通过查询当前会话的last_query_cost的值来得知Mysql计算的当前查询的成本。

mysql> select count(*) fromfilm_actor;+----------+

| count(*) |

+----------+

| 5462 |

+----------+

1 row in set (0.00sec)

mysql> show status like 'last_query_cost';+-----------------+-------------+

| Variable_name | Value |

+-----------------+-------------+

| Last_query_cost | 1040.599000 |

+-----------------+-------------+

这个结果表示mysql优化器认为大概需要做1040个数据页的随机查找才能完成上面的查询。这是根据一系列的统计信息计算得来的:每个表或者索引的页面个数,索引的基数(索引中不同值的数量),索引和数据行的长度,索引分布情况。

优化器在评估成本的时候并不考虑任何层面的缓存,它假设读取任何数据都需要一次磁盘I/O。

mysql优化器选错执行计划的原因:

统计信息不准确

执行计划中的成本估算不等同于实际执行的成本。

有的计划虽然要读取更多页,但是这些页在缓存中。

mysql的最有可能和你想的最优不一样。

比如你希望执行时间尽可能的短,而mysql只是基于成本模型选择的最优执行计划。

mysql从不考虑其他并发执行的查询,这可能会影响到当前查询速度。

mysql不会考虑不受其控制的操作的成本。

如执行存储过程或者用户自定义函数的成本

优化策略:

静态优化

直接对解析树进行分析,并完成优化。优化器通过一些简单的代数变换将where条件转换成另一种等价形式。静态优化在第一次完成后一直有效。可以认为这是一种"编译时优化"

动态优化

动态优化和查询的上下文有关。也和其他很多因素有关,例如where中的取值,索引中条目,等等。每次查询的时候都重新评估,可以认为这是一种"运行时优化"

mysql能够处理的优化类型

重新定义关联表的顺序。

将外联结转成内连接

使用等价变化规则

合并和减少一些比较,移除一些恒成立和一些恒不成立的判断

优化count(),min(),max(),min()就直接拿BTree树最左端数据行

预估并转换为常数表达式

覆盖索引扫描

子查询优化

提前终止查询

等值传播

在查询中添加hint,提示优化器,

优化器的局限性

1 关联子查询

mysql的子查询实现得非常糟糕;最糟糕的一类查询是where条件中包含IN()的子查询语句。

例如,我们希望找到sakila数据库中,演员actor_id为1,参演过的所有影片信息。很自然的,我们会按照下面的方式

mysql> select * from film where film_id in ( select film_id from film_actor where actor_id =1) \G;

我们一般认为,mysql会首先将子查询的actor_id=1的所有film_id都找到,然后再去做外部查询,如

select * from film where film_id in (1,23,25,106,140);

然而,mysql不是这样做的。

mysql会将相关的外层表压到子查询中,它认为这样可以更高效率地查找数据行。

当然我们可以使用连接替代子查询重写这个SQL,来优化;

mysql> explain select * from film f inner join film_actor fa where f.film_id=fa.film_id and actor_id =1;+----+-------------+-------+--------+------------------------+---------+---------+-------------------+------+-------+

| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |

+----+-------------+-------+--------+------------------------+---------+---------+-------------------+------+-------+

| 1 | SIMPLE | fa | ref | PRIMARY,idx_fk_film_id | PRIMARY | 2 | const | 19 | |

| 1 | SIMPLE | f | eq_ref | PRIMARY | PRIMARY | 2 | sakila.fa.film_id | 1 | |

+----+-------------+-------+--------+------------------------+---------+---------+-------------------+------+-------+

2 rows in set (0.00 sec)

如何用好关联子查询,很多时候,关联子查询也是一种非常合理,自然,甚至是性能最好的写法。

where in()肯定是不行的,但是 where exists()有时是可以的;

2 union的限制

有时,mysql无法将限制条件从外层"下推"到内层,这使得原本能够限制部分返回结果的条件无法应用到内层查询的优化上。

如果希望union的各个子句能够根据limit只取部分结果集,或者希望能够先拍下再合并结果集的话,就

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值