MySQL慢查询(上):你知道为啥会慢么?

我是架构精进之路,点击上方“关注”,坚持天天为你分享技术干货,私信我回复“01”,送你一份程序员成长进阶指南大礼包。程序员

发现的一些问题

问题1sql

在过去的半年时间里,研发团队内部尝试抓了一波儿慢查询SQL跟进处理率。发现有些同窗对于慢查询处理的思路就是看看有没有用到索引,没有用到就试图加一个,实在不行就甩锅给这种状况是历史设计问题或者自行断定为用户特殊操做下触发的小几率事件,随即使申请豁免掉... 其实问题没有根本上解决。数据库

问题2缓存

还有就是网络上常常能够看到一些相似这样的文章:性能优化

“慢SQL性能优化大全”服务器

“慢SQL性能优化看这篇就够了”...  微信

其实内容大同小异,要么建议加索引,要么建议重写SQL....网络

怎么说呢?知识点是对的,但不全面,这个很容易误导新同窗,哈哈哈。架构

本文初衷

在业务项目发展过程当中,咱们经常会面对要处理 MySQL 慢查询问题,那咱们应该如何分析解决问题呢?性能

部分同窗在处理MySQL慢查询时候主要思路是加索引来解决,确实加索引是一个很好的解决问题的手段,但不是所有。既然慢查询做为问题,那就须要明确问题发生缘由,和解决问题路径分析, 授人以鱼不如授人以渔,让咱们一块儿来解锁 🔓 下MySQL处理慢查询的正确姿式。

 

本文计划主要让你们搞明白查询SQL为何会变慢废话很少说,直接开干~

写在前面

在业务项目发展过程当中,咱们经常会面对要处理 MySQL 慢查询问题,那咱们应该如何分析解决问题呢?

部分同窗在处理MySQL慢查询时候主要思路是加索引来解决,确实加索引是一个很好的解决问题的手段,但不是所有。既然慢查询是问题,那就须要明确问题发生缘由,和解决问题路径分析。咱们一块儿来get下MySQL慢查询的正确姿式。

1、查询SQL执行到底经历了什么?

首先须要明确:一个查询SQL的执行到底经历了什么?

 

数据库执行SQL的大体流程以下:

  • 创建与MySQL服务器链接(基础)

  • 客户端发送查询SQL到数据库,数据库验证是否有执行的权限

  • MySQL服务器先检查查询缓存,若是命中了缓存,则当即返回存储在缓存中的结果,不然继续流转;

  • MySQL服务器语法解析器,进行词法与语法分析,预处理

  • 流转至查询优化器生成执行计划

  • 根据生成的执行计划,调用存储引擎暴露的API来执行查询

  • 将查询执行结果返回给客户端

  • 关闭MySQL链接

具体执行过程可能会因MySQL服务器具体配置和执行场景有一些差别。

1)如未开启应用查询缓存,则直接忽略查询缓存的检查;

2)执行过程当中,如同时对于被扫描的行可能加锁,同时也可能会被其余sql阻塞

2、查询SQL为何会慢?

咱们能够把查询SQL执行看作是一个任务的话,那它是由一些列子任务组成的,每一个子任务都存在必定的时间消耗。一般状况下,致使慢查询最根本的问题就是须要访问的数据太多,致使查询不可避免的须要筛选大量的数据

 

面对慢查询,咱们须要注意如下两点:

1)查询了过多不须要的数据

2)扫描了额外的记录

2.1 查询了过多不须要的数据

MySQL并非只返回须要的数据,实际上会返回所有结果集再进行计算。

尤为是多表关联查询 select * 的状况,咱们是否是真的须要所有的列呢?若是不是,那咱们直接指定对应字段就行了。

 

例如咱们要查询用户关联订单下的商品信息,以下所示:

SELECT *FROM users LEFT JOIN orders ON orders.user_id = users.user_id LEFT JOIN goods ON goods.good_id = orders.good_idWHERE users.name = 'zhangsan';

这将返回三个表的所有数据列,能够调整为仅取须要的列:

SELECT goods.title, goods.descriptionFROM users LEFT JOIN orders ON orders.user_id = users.user_id LEFT JOIN goods ON goods.good_id = orders.good_idWHERE users.name = 'zhangsan';

取出所有列,会让优化器没法完成索引覆盖扫描这类优化,还会为服务器带来额外的I/O、内存和CPU的消耗。

2.2 扫描了额外的记录

此种状况大部分属于索引应用不当形成的(包括:该建的索引没有建,或者未应用到最佳索引)。

示例表结构以下:

CREATE TABLE `test_table` ( `name` varchar(32) DEFAULT NULL, `desc` varchar(32) DEFAULT NULL, `age` int(16) DEFAULT NULL, `id` bigint(11) DEFAULT NULL, KEY `idx_age` (`age`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

存在索引 `idx_age` 的状况下,查询执行计划以下:

EXPLAIN SELECT * FROM test_table WHERE age = 10;

预估访问1行数据便可命中数据,如删除有效索引 `idx_age` 后则会变成全表扫描(ALL),预估须要扫描121524条记录才能完成这个查询,以下图所示:

小结

根据梳理 MySQL中的 SQL执行过程咱们发现,任何流程的执行都存在其执行环境和规则,其实产生慢SQL的本质是:咱们没有按照数据库的要求方式来执行SQL

主要致使慢查询最根本的问题就是须要访问的数据太多,致使查询不可避免的须要筛选大量的数据。

 


限于文章篇幅,同时为了你们更好的阅读体验,后面会连续产出系列文章:

MySQL慢查询(中)

    主要内容包括 如何定位慢查询问题几种实用解决方案

MySQL慢查询(

    主要内容包括 高性能查询难题优化内容点总结

最后,欢迎你们持续关注~

 


做者:架构精进之路,专一软件架构研究,技术学习与我的成长,关注并私信我回复“01”,送你一份程序员成长进阶指南大礼包。


「技术架构精进」专一架构研究,技术分享

 

Thanks for reading!

本文分享自微信公众号 - 架构精进之路(jiagou_jingjin)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索