【慢SQL性能优化】 一条SQL的生命周期 | 京东物流技术团队
一、 一条简单SQL在MySQL执行过程
一张简单的图说明下,MySQL架构有哪些组件和组建间关系,接下来给大家用SQL语句分析
例如如下SQL语句
SELECT department_id FROM employee WHERE name = 'Lucy' AND age > 18 GROUP BY department_id
其中name
为索引,我们按照时间顺序来分析一下
MySQL
服务器时,连接器验证客户端的用户名和密码,然后分配一个线程来处理客户端的请求。 MySQL
首先检查查询缓存中是否已有相同的查询及其结果。如果查询缓存中有匹配的查询结果,MySQL
将直接返回缓存的结果,而无需再次执行查询。但是,如果查询缓存中没有匹配的查询结果,MySQL
将继续执行查询。 name
索引进行查询,因为name
是索引列。 InnoDB
): employee
表的name
索引上进行等值查询,因查询全部列,涉及到回表访问磁盘。 InnoDB
的缓冲池(Buffer Pool
)中是否已有所需的数据页。如果缓冲池中有符合条件的数据页,直接使用缓存的数据。如果缓冲池中没有所需的数据页,从磁盘加载数据页到缓冲池中。 name
。这是因为基于索引条件加载到内存中是数据页,数据页中也有可能包含不满足索引条件的记录,所以还要再判断一次name
条件,满足name
条件则继续判断age > 18
过滤条件。 department_id
对满足条件的记录进行分组。 在整个查询执行过程中,这些组件共同协作以高效地执行查询。客户端负责发送查询,连接器管理客户端连接,查询缓存尝试重用先前查询结果,解析器负责解析查询,优化器选择最佳执行计划,执行器执行优化器选择的计划,存储引擎(如InnoDB
)负责管理数据存储和访问。这些组件的协同作用使得MySQL
能够高效地执行查询并返回结果集。
根据索引列过滤条件加载索引的数据页到内存这个操作是存储引擎做的。加载到内存中之后,执行器会进行索引列和非索引列的过滤条件判断。
二、 查询SQL关键字执行顺序
执行顺序,如下:
1、对存储引擎的操作
(1)FROM
:用于查询SQL的数据表。执行器会根据优化器选择的执行计划从存储引擎中获取相关表的数据。
(2)ON
: 与JOIN
一起使用,用于指定连接条件。执行器会根据ON
给定的条件条件从存储引擎获取匹配条件的记录。如果连接条件涉及到索引列,存储引擎会使用索引进行优化。
(3)JOIN
:指定表之间连接方式(如INNER JOIN
,LEFT JOIN
等)。执行器会根据优化器选择的执行计划,从存储引擎中获取连接表数据。然后执行器根据JOIN
连接类型和ON
连接条件,对数据连接处理。
(4)WHERE
:执行器对从存储引擎返回的数据进行过滤,只保留满足WHERE
子句条件的记录。过滤条件如有索引,存储引擎层会通过索引过滤后返回。
2、对返回结果集的操作
(5)GROUP BY
:执行器对满足WHERE
条件的记录按照GROUP BY
指定的列分组。
(6)HAVING
:执行器在执行分组后,根据HAVING
条件对分组后的记录再次过滤。
(7)SELECT
:执行器根据优化器选择的执行计划和指定列获取查询结果。
(8)DISTINCT
:执行器对查询结果进行去重,只返回不重复的记录。
(9)ORDER BY
:执行器对查询结果按照ORDER BY
子句中指定的列进行排序。
(10)LIMIT
:执行器根据LIMIT
子句中指定的限制条件对查询结果进行截断,只返回部分记录
三、表关联查询SQL在MySQL中的执行过程
SELECT s.id, s.name, s.age, es.subject, es.score FROM employee s JOIN employee_score es ON s.id = es.employee_id WHERE s.age >18 AND es.subject_id =3 AND es.score >80;
这个例子中,subject_id
和score
是联合索引,age
是索引。 我们按照时间顺序来分析一下
MySQL
服务器时,连接器负责建立和管理连接。它验证客户端提供的用户名和密码,确定客户端具有相应的权限,然后建立连接。 MySQL
服务器在处理查询之前,会先检查查询缓存。如果查询缓存中已经存在该结果集,服务器将直接返回缓存中的结果。 SQL
语法正确性。解析器会将查询语句分解成多个组成部分,例如表、列、条件等。在这个示例中,解析器会识别出涉及的表(employee
和employee_score
)以及需要的列(id、name、age、subject、score
)。 age
索引和subject_id
与score
的联合索引。对于连接操作,优化器还要决定连接策略,例如是否使用Nested-Loop Join
或Hash Join
等一些连接策略。优化器还会根据表的大小、索引、查询条件和统计信息来决定哪张表作为驱动表,以及选择最佳的连接策略。例如,如果两个表的大小差异很大,Nested-Loop Join
可能是一个好的选择,而对于大小相似的两个表,Hash Join
或Sort-Merge Join
可能更加高效。 InnoDB
):管理数据存储和检索。存储引擎首先接收来自执行器的请求,该请求可能是基于优化器的执行计划。 employee
表进行索引扫描(使用age
索引),然后对employee_score
表进行索引扫描(使用subject_id
和score
的联合索引)。 employee
索引中会找到满足age > 18
条件的记录。在employee_score
索引中找到满足subject_id = 3 AND score > 80
条件的记录。 InnoDB Buffer Pool
),看这些数据页是否已经存在于内存中。如果已经存在,则无需再次从磁盘加载。如果不存在,存储引擎会将这些数据页从磁盘加载到缓冲池中。 employee
表和employee_score
表的数据行连接起来。 age > 18、subject_id = 3、score > 80
)的数据行。 前面说过,根据存储引擎根据索引条件加载到内存的数据页有多数据,可能有不满足索引条件的数据,如果执行器不再次进行索引条件判断, 则无法判断哪些记录满足索引条件的,虽然在存储引擎判断过了,但是在执行器还是会有索引条件 age > 18、subject_id = 3、score > 80
的判断。
我们再以全局视野来分析一下
- 确定驱动表: 首先,
MySQL
优化器会选择一个表作为"驱动表"。通常,返回记录数较少的表会被选为驱动表。假设employee_score
表中满足subject_id = 3 AND score > 80
条件的记录数量较少,那么这张表可能被选为驱动表。这是优化器的工作,它预估哪个表作为驱动表更为高效,制定执行计划。虽然驱动表的选择很大程度上是基于预估的返回记录数,但实际选择还会受其他因素影响,例如表之间的连接类型、可用的索引等。 - 使用驱动表的索引进行筛选: 优化器会首先对驱动表进行筛选。如果
employee_score
是驱动表,优化器会使用subject_id
和score
的联合索引来筛选出subject_id = 3 AND score > 80
的记录。这是执行器按照优化器的计划向存储引擎发出请求,获取需要的数据。存储引擎负责访问索引,并根据索引定位到实际的数据页,从而获取数据行。 - 连接操作: 执行器会基于上一步从驱动表中筛选出的记录对另一个表(即
employee
表)进行连接。这时,执行器会使用employee
表上的索引(如id
索引)来高效地找到匹配的记录。 - 进一步的筛选: 在连接的过程中,执行器会考虑
employee
表的其他筛选条件,如age > 18
,通常连接后才过滤筛选,这也是执行器的工作,执行器在连接过程中或之后,根据优化器制定的计划进一步筛选结果集。但是这里employee
表的age
索引其叶子节点包含age
和主键id
信息,在进行连接时,可以直接按照age
范围扫描该索引,利用其叶子节点中的id
信息进行高效的JOIN
操作,因此在连接时就完成筛选,这个过程由MySQL
优化器自动完成。从上面可以看到,当存在可以被利用的索引时,MySQL
可以在连接过程中执行这些过滤操作。 - 返回结果: 这是执行器最后的步骤,返回最终的查询结果。
四、总结
本文采用一张简单的架构图说明了MySQL查询中使用的组件和组件间关系。
解析了一条sql语句从客户端请求mysql服务器到返回给客户端的整个生命周期流程。
列举了单表sql、关联表sql 两种不同SQL在整个生命周期中的执行顺序和及内部组件逻辑关系。
通过如上案例的解析可以让开发者们掌握到单表sql、关联表sql的底层sql知识,为理解慢sql的产生和优化鉴定基础。
作者:京东物流 高峰
来源:京东云开发者社区 自猿其说Tech 转载请注明来源

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
HelloGitHub 社区动态,开启新的篇章!
今天这篇文章是 HelloGitHub 社区动态的第一篇文章,所以我想多说两句,聊聊为啥开启这个系列。 我是 2016 年创建的 HelloGitHub,它从最初的一份分享开源项目的月刊,现如今已经成长为 7w+ Star 的开源项目、1w+ 用户的开源社区、全网 50w+ 的自媒体。 我本是一名普通的程序员,三流的技术水平、毫无文笔、开源门外汉,起初连 Git 都不会,也不知道什么是开源,就一个猛子扎进来做了 HelloGitHub。为了想让更多人看到 HelloGitHub 月刊,稀里糊涂地就做起了“自媒体”。我为了圆自己的站长梦,饿着肚子咬牙重构了 HelloGitHub.com 网站,从最初的 Web 1.0 的月刊展示,升级到了 Web 2.0 的开源社区。 聪明的人追着风口跑,很容易就赚到钱了。像我这种愚笨的人,只做「分享开源项目」这一件事情,就花了 7 年的事情,钱没赚到人还瘦了两圈😂。 有人说我不会玩流量,确实我不会,因为在我眼里每一次点击、每一个阅读、每一位粉丝背后都是我的一位朋友。说起来真是惭愧,就是我和朋友们的沟通太少了,因为我总想一个人、一台电脑、一把键盘,做...
- 下一篇
有效降低数据库存储成本方案与实践 | 京东云技术团队
背景 随着平台的不断壮大,业务的不断发展,后端系统的数据量、存储所使用的硬件成本也逐年递增。从发展的眼光看,业务与系统要想健康的发展,成本增加的问题必须重视起来。目前业界普遍认同开源节流大方向,很多企业部门也针对数据库存储降低成本进行了尝试,有的删数据、有的删索引、有的做压缩、有的做冷热分离,方式方法层出不穷,不一而足,然而不是因为收效甚微而导致没有达到预期,就是由于改造成本过大,投入周期过长,导致投产比不高,虚耗人力。笔者目前所在部门也正好面临同一问题,一个账单系统,存储数据超过100T,占用40台物理机,40库,一个分表就有20480张,这样的分表有4个,这种存储架构相对臃肿,要想实践降低成本的诉求,难度很高。 本文主要介绍方法,方案也会涉及,但不会特别细致的展开。 挑战 核心挑战有以下几个: 数据安全问题:无论是删数据,做压缩,冷热分离,对于已经占据100T磁盘空间的存储系统都是困难的操作,一个不小心,数据丢失了,或者无法正常获取数据了,这些问题对部门、对公司都会造成巨大损失。 系统稳定性问题:一些有效的降低存储空间的方案,如数据序列化、压缩等,无外乎是用时间换空间,牺牲性能换取...
相关文章
文章评论
共有0条评论来说两句吧...