热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MySQL的server层和存储引擎层是如何交互的

为了故事的顺利发展,我们先创建一个表:

SQL 的全称是 Structured Query Language ,翻译成中国话就是 结构化查询语言 。这是一种声明式的语法,何为声明式?可以联想一下我们生活中的老板,老板在布置任务的时候会告诉你:小王啊,今天把这些砖从A地搬到B地啊,然后就没然后了。老板并不关心你是用手抬,还是用车拉,老板只关心结果:你把砖搬过去就好了。我们之于数据库而言,就是一个老板, SQL 语句就是我们给数据库下达的任务,至于具体数据库怎么执行我们并不关心,我们只关心最后数据库给我们返回的结果。

对于设计数据库的人而言,语句怎么执行就得好好考虑了,老板不操心,事儿总还得干。设计 MySQL 的大叔人为的把 MySQL 分为 server 层和 存储引擎 层,但是什么操作是在 server 层做的,什么操作是在 存储引擎 层做的大家可能有些迷糊。本文将以一个实例来展示它们二者各自负责的事情。

准备工作

为了故事的顺利发展,我们先创建一个表:

CREATE TABLE hero (
    id INT,
    name VARCHAR(100),
    country varchar(100),
    PRIMARY KEY (id),
    KEY idx_name (name)
) Engine=InnoDB CHARSET=utf8;

我们为 hero 表的 id 列创建了聚簇索引,为 name 列创建了一个二级索引。这个 hero 表主要是为了存储三国时的一些英雄,我们向表中插入一些记录:

INSERT INTO hero VALUES
    (1, 'l刘备', '蜀'),
    (3, 'z诸葛亮', '蜀'),
    (8, 'c曹操', '魏'),
    (15, 'x荀彧', '魏'),
    (20, 's孙权', '吴');

现在表中的数据就是这样的:

mysql> SELECT * FROM hero;
+----+------------+---------+
| id | name       | country |
+----+------------+---------+
|  1 | l刘备      | 蜀      |
|  3 | z诸葛亮    | 蜀      |
|  8 | c曹操      | 魏      |
| 15 | x荀彧      | 魏      |
| 20 | s孙权      | 吴      |
+----+------------+---------+
5 rows in set (0.00 sec)

准备工作就做完了。

正文

一条语句在执行之前需要生成所谓的执行计划,也就是该语句将采用什么方式来执行(使用什么索引,采用什么连接顺序等等),我们可以通过 Explain 语句来查看这个执行计划,比方说对于下边语句来说:

mysql> EXPLAIN SELECT * FROM hero WHERE name <'s孙权' AND country = '蜀';
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+------------------------------------+
| id | select_type | table | partitions | type  | possible_keys | key      | key_len | ref  | rows | filtered | Extra                              |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+------------------------------------+
|  1 | SIMPLE      | hero  | NULL       | range | idx_name      | idx_name | 303     | NULL |    2 |    20.00 | Using index condition; Using where |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+------------------------------------+
1 row in set, 1 warning (0.03 sec)

输出结果的 key 列值为 idx_name type 列的值为 range ,表明会针对 idx_name 二级索引进行一个范围查询。很多同学在这里有一个疑惑:到底是一次性把所有符合条件的二级索引都取出来之后再统一进行回表操作,还是每从二级索引中取出一条符合条件的记录就进行回表一次?其实 server层和存储引擎层的交互是以记录为单位的 ,上边这个语句的完整执行过程就是这样的:

  1. server层第一次开始执行查询,把条件 name <'s孙权' 交给存储引擎,让存储引擎定位符合条件的第一条记录。

  2. 存储引擎在二级索引 idx_name 中定位 name <'s孙权' 的第一条记录,很显然第一条符合该条件的二级索引记录的 name 列的值为 'c曹操' 。然后需要注意,我们看到 EXPLAIN 语句的输出结果的 Extra 列有一个 Using index condition 的提示,这表明会将有关 idx_name 二级索引的查询条件放在存储引擎层判断一下,这个特性就是所谓的 索引条件下推 (Index Condition Pushdown,简称 ICP )。很显然这里的 ICP 条件就是 name <'s孙权' 。有的同学可能会问这不就是脱了裤子放屁么, name 值为 'c曹操' 的这条记录就是通过 name <'s孙权' 这个条件定位的,为啥还要再判断一次?这就是设计 MySQL 的大叔的粗暴设计,十分简单,没有为啥~

    小贴士: 对于使用二级索引进行等值查询的情况有些许不同,比方说上边的条件换成`name = 's孙权'`,对于等值查询的这种情况,设计MySQL的大叔在InnoDB存储引擎层有特殊的处理方案,是不作为ICP条件进行处理的。

    然后拿着该二级索引记录中的主键值去回表,把完整的用户记录都取到之后返回给 server层 (也就是说得到一条二级索引记录后立即去回表,而不是把所有的二级索引记录都拿到后统一去回表)。

  3. 我们的执行计划输出的 Extra 列有一个 Using Where 的提示,意味着server层在接收到存储引擎层返回的记录之后,接着就要判断其余的WHERE条件是否成立(就是再判断一下 country = '蜀' 是否成立)。如果成立的话,就直接发送给客户端。

    小贴士: 什么?发现一条记录符合条件就发送给了客户端?那为什么我的客户端不是一条一条的显示查询结果,而是一下子全部展示呢?这是客户端软件的鬼,人家规定在接收完全部的记录之后再展示而已。

    如果不成立的话,就跳过该条记录。

  4. 接着server层向存储引擎层要求继续读刚才那条记录的下一条记录。

  5. 因为每条记录的头信息中都有 next_record 的这个属性,所以可以快速定位到下一条记录的位置,然后继续判断 ICP 条件,然后进行回表操作,存储引擎把下一条记录取出后就将其返回给server层。

  6. 然后重复第3步的过程,直到存储引擎层遇到了不符合 name <'s孙权' 的记录,然后向server层返回了读取完毕的信息,这时server层将结束查询。

这个过程用语言描述还是有点儿啰嗦,我们写一个超级简化版的伪代码来瞅瞅(注意,是超级简化版):

first_read = true;  //是否是第一次读取
while (true) {

    if (first_read) {
        first_read = false;
        err = index_read(...);  //调用存储引擎接口,定位到第一条符合条件的记录;
    } else {
        err = index_next(...); //调用存储引擎接口,读取下一条记录
    }
    
    if (err = 存储引擎的查询完毕信息) {
        break;  //结束查询
    }
    
    if (是否符合WHERE条件) {
        send_data();    //将该记录发送给客户端;
    } else {
        //跳过本记录
    }
}

上述的伪代码虽然很粗糙,但也基本表明了意思哈~ 之后有机会我们再唠叨唠叨使用临时表的情况以及使用 filesort 的情况是怎么执行的。

题外话

想了解更多关于MySQL是怎样运行的细节,可以直接扫码观看:

MySQL的server层和存储引擎层是如何交互的

动动大拇指,长按关注小青蛙,全全全全都是干货哦哦哦:

MySQL的server层和存储引擎层是如何交互的


以上所述就是小编给大家介绍的《MySQL的server层和存储引擎层是如何交互的》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 我们 的支持!


推荐阅读
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
author-avatar
wan乄etsnyd
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有