摘要:一条SQL如何被MySQL架构中的各个组件操作执行的,执行器做了什么?存储引擎做了什么?表关联查询是怎么在存储引擎和执行器被分步执行的?本文带你探探究竟!
简单用一张图说明下,MySQL架构有哪些组件,此时此刻呢给大家用SQL语句分析
假如SQL语句是这样
SELECT class_no FROM student WHERE name = 'lcy' AND age > 18 GROUP BY class_no
其中name为索引,我们按照时间顺序来分析一下
解析查询语句,检查语法.
验证表名和列名的正确性.
生成查询树.
负责实际执行索引扫描,如在student表的name索引上进行等值查询,因查询全部列,涉及到回表访问磁盘.
在访问磁盘之前,先检查InnoDB的缓冲池(Buffer Pool)中是否已有所需的数据页.如果缓冲池中有符合条件的数据页,直接使用缓存的数据.如果缓冲池中没有所需的数据页,从磁盘加载数据页到缓冲池中.
根据class_no对满足条件的记录进行分组.
根据索引列过滤条件加载索引的数据页到内存这个操作是存储引擎做的.加载到内存中之后,执行器会进行索引列和非索引列的过滤条件判断.
根据执行顺序,如下:
(1)FROM:FROM子句用于指定查询所涉及的数据表.在查询执行过程中,执行器需要根据优化器选择的执行计划从存储引擎中获取指定表的数据.
(10)LIMIT:执行器根据LIMIT子句中指定的限制条件对查询结果进行截断,只返回部分记录
SELECT s.id, s.name, s.age, sc.subject, sc.score FROM student s JOIN score sc ON s.id = sc.student_id WHERE s.age > 18 AND sc.subject = 'math' AND sc.score > 80;
这个例子中,student_id和subject是联合索引,age是索引.
我们按照时间顺序来分析一下
存储引擎首先接收来自执行器的请求.请求可能包括获取满足查询条件的数据行,以及使用哪种扫描方法(如全表扫描或索引扫描).
假设执行器已经决定使用索引扫描.在这个示例中,存储引擎可能会先对student表进行索引扫描(使用age索引),然后对score表进行索引扫描(使用student_id和subject的联合索引).
一旦找到了满足条件的记录,存储引擎需要将这些记录所在的数据页从磁盘加载到内存中.存储引擎首先检查缓冲池(InnoDB Buffer Pool),看这些数据页是否已经存在于内存中.如果已经存在,则无需再次从磁盘加载.如果不存在,存储引擎会将这些数据页从磁盘加载到缓冲池中.
加载到缓冲池中的记录可以被多个查询共享,这有助于提高查询效率.
在内存中执行连接操作,将student表和score表的数据行连接起来.
先看例子
查询1
SELECT s.id, s.name, s.age, sc.subject, sc.score FROM student s LEFT JOIN score sc ON s.id = sc.student_id WHERE s.age > 18 AND sc.subject = 'math' AND sc.score > 80;
SELECT s.id, s.name, s.age, sc.subject, sc.score FROM (SELECT id, name, age FROM student WHERE age > 18) s LEFT JOIN (SELECT student_id, subject, score FROM score WHERE subject = 'math' AND score > 80) sc ON s.id = sc.student_id
SELECT s.id, s.name, s.age, sc.subject, sc.score FROM student s LEFT JOIN score sc ON s.id = sc.student_id AND s.age > 18 AND sc.subject = 'math' AND sc.score > 80;
分析一下
从运行结果来看,对于查询1
SELECT s.id, s.name, s.age, sc.subject, sc.score FROM student s LEFT JOIN score sc ON s.id = sc.student_id WHERE s.age > 18 AND sc.subject = 'math' AND sc.score > 80;
在这个查询中,首先执行LEFT JOIN,将student表和score表连接起来.连接操作是基于s.id = sc.student_id条件进行的.LEFT JOIN操作会保留左表(student表)中的所有行,即使它们在右表(score表)中没有匹配的行.如果右表中没有匹配的行,那么右表的列将显示为NULL.
SELECT s.id, s.name, s.age, sc.subject, sc.score FROM (select id, name, age from student where age > 18) s LEFT JOIN (select subject, score from score where subject = 'math' AND score > 80) sc ON s.id = sc.student_id
此时此刻呢,执行LEFT JOIN操作,将过滤后的s和sc子查询的结果集连接起来,基于s.id = sc.student_id条件.因为LEFT JOIN操作会保留左表(s子查询的结果集)中的所有行,右表为NULL的记录包含了.
结果差异:
我们分析一下这两个查询在MySQL架构中各个组件中执行的区别
对于查询1:
SELECT s.id, s.name, s.age, sc.subject, sc.score FROM student s LEFT JOIN score sc ON s.id = sc.student_id WHERE s.age > 18 AND sc.subject = 'math' AND sc.score > 80;
查询缓存:检查缓存是否存在此查询的结果.如果有,直接返回结果.否则,继续执行.
解析器:解析查询语句,检查语法是否正确.
优化器:对查询进行优化,生成执行计划,决定连接和过滤条件的顺序等.
执行器:开始请求执行查询.
存储引擎(InnoDB):从磁盘或者缓冲池读取满足条件的数据行(s.id = sc.student_id),因为是left join,所以即便sc.student_id为null也会被关联.
当查询包含索引列的条件时,MySQL的存储引擎会首先利用索引在磁盘上定位到满足索引条件的记录.接着,将这些索引数据对应的数据页加载到内存中的缓冲池.然后,执行器在内存中对这些记录进行进一步的过滤,根据索引条件和非索引列的条件来过滤数据.
当查询涉及到非聚集索引时,需要回表的操作会导致聚集索引和非聚集索引都被加载到内存中.但是,如果查询只涉及到聚集索引(如主键查询),那么只需要加载聚集索引的数据页即可.
SELECT s.id, s.name, s.age, sc.subject, sc.score FROM (SELECT id, name, age FROM student WHERE age > 18) s LEFT JOIN (SELECT student_id, subject, score FROM score WHERE subject = 'math' AND score > 80) sc ON s.id = sc.student_id
优化器:决定使用哪些索引进行查询优化,以及确定连接顺序.
执行器:开始请求执行子查询.
走?PRIMARY索引(聚集索引)和全表扫描有什么区别?呢?准确来说,使用InnoDB存储引擎的情况下,全表扫描的数据和聚集索引的数据在InnoDB表空间中的存储位置是相同的,也就是说它们的内存地址也是相同的.所以你也可以理解为,他们其实都是在聚集索引上操作的(聚集索引B◆树的叶子结点是根据主键排好序的完整的用户记录,包含表里的所有字段),区别就在于
全表扫描将聚集索引B◆树的叶子结点从左到右依次顺序扫描并判断条件.
默认情况下,InnoDB使用一个名为ibdata1的共享表空间文件存储所有的数据和索引,包括聚集索引和二级索引(又称非聚集索引或辅助索引).
以上就是土嘎嘎小编为大家整理的一条SQL如何被MySQL架构中的各个组件操作执行的?相关主题介绍,如果您觉得小编更新的文章只要能对粉丝们有用,就是我们最大的鼓励和动力,不要忘记讲本站分享给您身边的朋友哦!!