MYSQL的server层和存储引擎层分析

2023-11-12

转自:微点阅读 https://www.weidianyuedu.com

SQL的全称是Structured Query Language,翻译成中国话就是结构化查询语言。这是一种声明式的语法,何为声明式?

对于设计数据库的人而言,语句怎么执行就得好好考虑了,老板不操心,事儿总还得干。设计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孙权"交给存储引擎,让存储引擎定位符合条件的第一条记录。

  1. 存储引擎在二级索引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层(也就是说得到一条二级索引记录后立即去回表,而不是把所有的二级索引记录都拿到后统一去回表)。

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

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

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

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

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

  1. 然后重复第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的情况是怎么执行的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MYSQL的server层和存储引擎层分析 的相关文章

  • AMQP Spring 集成错误处理

    我的集成流程如下所示 Bean public IntegrationFlow auditFlow Qualifier eventLoggingConnectionFactory ConnectionFactory connectionFac
  • 始终等待页面加载到 PageObjects 上

    因此 当出现问题时 我只是创建了一个简单的 selenium JBehave 代码 我将首先发布简化的代码 然后稍后解释我的问题是什么 所以这里我们有一个简单的 AbstractClass 它将在我的 PageObjects 上继承 此类仅
  • 有没有办法让Maven自动下载快照版本?

    所以我有一个项目依赖于另一个项目的快照版本 依赖关系是
  • 如何将日期字符串解析为Date? [复制]

    这个问题在这里已经有答案了 如何将下面的日期字符串解析为Date object String target Thu Sep 28 20 29 30 JST 2000 DateFormat df new SimpleDateFormat E
  • 对于数据库来说,选择正确的数据类型会影响性能吗?

    如果是这样 为什么 我的意思是 tinyint 的搜索速度比 int 快吗 如果是这样 性能上的实际差异是什么 是的 根据数据类型 它确实有所不同 int vs tinyint不会在速度上产生明显的差异 但会在数据大小上产生差异 假设tin
  • Java 8 Stream - 并行执行 - 不同的结果 - 为什么?

    假设我有一个List
  • Java ArrayList 和 HashMap 动态

    有人可以提供一个创建Java的例子吗ArrayList and HashMap在飞行中 所以而不是做一个add or put 实际上在类实例化时为数组 哈希提供种子数据 举个例子 类似于 PHP 的例子 array array 3 1 2
  • 如何在 phpmyadmin 中创建 MySQL 触发器

    我想在 MySQL 中创建一个触发器 我运行以下命令 mysql gt delimiter mysql gt CREATE TRIGGER before insert money BEFORE INSERT ON money gt FOR
  • 自 JRE 1.7.0_25 起,Batik 无法进行转换

    自从我更新到 JAVA 1 7 0 25 以来 蜡染在应用转换时会抛出异常 堆栈跟踪是 java awt image ImagingOpException Unable to transform src image at java awt
  • 显示表 FULLTEXT 索引列

    我希望运行一个查询 该查询将返回表中全文索引的列列表 该表采用 MyISAM 格式 我将使用 php 来构建查询 理想情况下 我会运行查询 它会返回信息 以便我可以构造一个以逗号分隔的列字符串 例如 名 姓 电子邮箱 这在 MySQL 中可
  • 在 Apache Servicemix 4 中的 OSGi 包之间共享配置文件?

    有人能够在 SMX4 中的两个或多个捆绑包之间成功共享配置吗 我正在寻找的是这样的 有一个文件 SMX HOME etc myconfiguration cfg 使此配置 可用 以便使用 Spring dm 通过 OSGi 配置管理将其注入
  • 为什么 MySQL 创建带有 _seq 后缀的表?

    我创建了一个 InnoDB 表 名为foo在 MySQL 中 一旦我对表执行插入操作 我就会看到另一个表foo seq被建造 如果我删除自动生成的表 它会在下一次插入后出现 是什么原因造成的 听起来像是正在创建一个序列 您是否有自动生成的主
  • gwt 文本框添加更改处理程序

    我有一个从设计师那里收到的文本框 但是我在 GWT 中编写了操作 问题是文本框为空 但是当通过按下按钮用值填充文本框时 将显示警报框 通知值已更改 但没有成功 帮助我 TextBox zip1 null function onModuleL
  • Web 服务客户端的 AXIS 与 JAX-WS

    我决定用Java 实现Web 服务客户端 我已经在 Eclipse 中生成了 Axis 客户端 并使用 wsimport 生成了 JAS WS 客户端 两种解决方案都有效 现在我必须选择一种来继续 在选择其中之一之前我应该 考虑什么 JAX
  • 对于双核手机,availableProcessors() 返回 1

    我最近购买了一部 Moto Atrix 2 手机 当我尝试查看手机中的处理器规格时 Runtime getRuntime availableProcessors 返回 1 proc cpuinfo 也仅包含有关处理器 0 的信息 出于好奇
  • java mysql 准备好的语句

    我正在尝试使用 java 向数据库中进行简单的插入 它告诉我我的 sql 语法已关闭 但是 当我复制打印出来的字符串并将其放入 phpmyadmin 中的 sql 命令中时 它会正确执行该命令 并且我似乎无法弄清楚 java 中的字符串查询
  • 空检查时可能未初始化错误

    我正在检查变量是否已初始化 但此时 netbeans 给了我variable reader might not have been initialized警告 我该如何解决 抑制这个问题 这是我的代码 摘要 final Reader rea
  • Volley 在第一次调用方法时返回 null

    我正在尝试使用 volley 从服务器检索数据 但是当我第一次调用此方法时 我收到服务器的响应 但该方法返回 null 如果我第二次调用它 我会得到最后的响应 public String retrieveDataFromServer Str
  • 将 SQL 数据中的一行映射到 Java 对象

    我有一个 Java 类 其实例字段 以及匹配的 setter 方法 与 SQL 数据库表的列名相匹配 我想优雅地从表中获取一行 到 ResultSet 中 并将其映射到此类的实例 例如 我有一个 Student 类 其中包含实例字段 FNA
  • removeall 和removeif 的用例

    我找到了这个 fun main val list MutableList

随机推荐