一条SQL查询语句是如何执行的?

MySQL是典型的 C/S架构(客户端/服务器架构),客户端进程向服务端进程发送一段文本(MySQL指令),服务器进程进行语句处理然后返回执行结果。

问题来了。服务器进程对客户端发送的请求究竟做了什么处理呢?本文以查询请求为例,讲解MySQL服务器进程的处理流程。

如下图所示,服务器进程在处理客户端请求时大致需要三个步骤:

[En]

As shown in the following figure, the server process roughly needs to take three steps when processing client requests:

  • 处理连接
  • 解析与优化
  • 存储引擎

接下来,让我们仔细看看这三个步骤都做了些什么。

[En]

Next, let’s take a closer look at what has been done in these three steps.

一条SQL查询语句是如何执行的?

1. 处理连接

客户端向服务器发送请求,最终收到响应,本质上是进程间通信的过程。

[En]

The client sends a request to the server and finally receives a response, which is essentially a process of inter-process communication.

MySQL有专门用于处理连接的模块——连接器。

1.1 客户端和服务端的通信方式

1.1.1 TCP/IP协议

TCP/IP协议是MySQL客户端和服务器最常用的通信方式。

我们平时所说的MySQL服务器默认监听的端口是 3306,这句话的前提是客户端进程和服务器进程使用的是 TCP/IP协议进行通信。

我们在使用 mysql命令启动客户端程序时,只要在 -h参数后跟随IP地址作为服务器进程所在的主机地址,那么通讯方式便是 TCP/IP协议。

如果客户端进程和服务器进程位于同一台主机,且要使用 TCP/IP协议进行通信,则IP地址需要指定为127.0.0.1,而不能使用localhost

1.1.2 UNIX域套接字

如果客户端进程和服务器进程都位于类UNIX操作系统(MacOS、Centos、Ubuntu等)的主机之上,并且在启动客户端程序时没有指定主机名,或者指定的主机名为 localhost,又或者指定了 --protocol=socket的启动参数,那么客户端进程和服务器进程就会使用 UNIX域套接字进行进程间通信。

MySQL服务器进程默认监听的 UNIX域套接字文件为 /temp/mysql.sock,客户端进程启动时也默认会连接到这个UNIX域套接字文件之上。

如果不明白 UNIX域套接字到底是什么也没关系,只要知道这是进程之间的一种通讯方式就可以了,这里提及的主要目的是希望读者知晓MySQL客户端和进程通讯方式不止于 TCP/IP协议

1.1.3 命名管道和共享内存

如果你的MySQL是安装在Windows主机之上,客户端和服务器进程可以使用命名管道和共享内存的方式进行通信。

但是,要使用这些通信方法,您需要在服务器和客户端启动时添加一些启动参数。

[En]

However, to use these communication methods, you need to add some startup parameters when the server and client start.

  • 使用命名管道进行通信。需要在启动服务器时添加 --enable-named-pipe参数,同时在启动客户端进程时添加 --pipe或者 --protocol=pipe参数
  • 使用共享内存进行通信。需要在启动服务器时添加 --shared-memory参数,启动成功后,共享内存便成为本地客户端程序的默认连接方式;也可以在启动客户端进程的命令中加上 --protocol=memory参数明确指定使用共享内存进行通信

如果不明白命名管道和共享内存到底是什么没关系,只要知道这是进程之间的一种通讯方式就可以了,这里提及的主要目的是希望读者知晓MySQL客户端和进程通讯方式不止于 TCP/IP协议

1.2 权限验证

确认通信模式并成功建立连接后,连接器将开始使用您的用户名和密码验证您的身份。

[En]

After confirming the mode of communication and successfully establishing the connection, the connector will begin to verify your identity, using your user name and password.

  • 如果用户名或密码不正确,客户端连接将立即断开
    [En]

    if the user name or password is incorrect, the client connection will be disconnected immediately*

  • 如果用户名和密码认证通过,连接器将在权限表中检查当前登录用户的权限。之后,此连接中的权限判断逻辑将取决于此时读取的权限。
    [En]

    if the user name and password authentication is passed, the connector will check the permissions of the current login user in the permissions table. After that, the permission judgment logic in this connection will depend on the permissions read at this time.*

1.3 查看MySQL连接

每当客户端连接到服务器时,服务器进程都会创建一个单独的线程来处理当前的客户端交互。

[En]

Whenever a client connects to the server, the server process creates a separate thread to handle the current client interaction.

那么如何查看MySQL当前所有的连接?

mysql> show global status like 'Thread%';

+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_cached    | 0     |
| Threads_connected | 1     |
| Threads_created   | 1     |
| Threads_running   | 1     |
+-------------------+-------+

各字段含义如下表

字段 含义 Threads_cached 缓存中的线程连接数 Threads_connected 当前打开的连接数 Threads_created 为处理连接创建的线程数 Threads_running 非睡眠状态的连接数,通常指并发连接数

连接建立后,服务器等待客户端发送请求,除非客户端主动断开连接。但是,创建和维护线程会消耗服务器资源,因此服务器会断开长期处于非活动状态的客户端连接。

[En]

After the connection is established, the server waits for the client to send a request unless the client actively disconnects. However, the creation and maintenance of threads consume server resources, so the server will disconnect client connections that have been inactive for a long time.

有2个参数控制这个自动断开连接的行为,每个参数都默认为28800秒,8小时。

-- 非交互式超时时间,如JDBC连接
mysql> show global variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 28800 |
+---------------+-------+

-- 交互式超时时间,如数据库查看工具Navicat等
mysql> show global variables like 'interactive_timeout';
+---------------------+-------+
| Variable_name       | Value |
+---------------------+-------+
| interactive_timeout | 28800 |
+---------------------+-------+

既然连接消耗资源,那是不是MySQL的最大连接数也有默认限制呢?没错!默认最大连接数为151。

mysql> show variables like 'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 151   |
+-----------------+-------+

题外话:细心的读者可能会发现MySQL某些查询语句带有 global关键字,这个关键字有什么含义呢?

MySQL的系统变量有两个作用范围(不区分大小写),分别是

  • GLOBAL(全局范围):变量的设置影响服务器和所有客户端
  • SESSION(会话范围):变量的设置仅影响当前连接(会话)

但是并非每个参数都具有两个作用范围,比如允许同时连接到服务器的客户端的数量 max_connections就只有全局级别。

当没有带作用范围关键字时,默认是 SESSION级别,包括查询和修改操作。

例如,修改参数后,在当前窗口中生效,但在其他窗口中不生效。

[En]

For example, after modifying a parameter, it takes effect in the current window, but not in other windows.

show VARIABLES like 'autocommit';
set autocommit = on;

因此,如果只是临时修改,请使用 SESSION级别,如果需要当前设置在其他会话中生效,需要使用 GLOBAL关键字。

此时,服务器进程已经与客户端进程建立了连接,下一步是处理来自客户端的请求。

[En]

At this point, the server process has established a connection with the client process, and the next step is to process the request from the client.

2. 解析与优化

在收到客户端的请求后,服务器还需要进行查询缓存、词法语法解析和预处理以及查询优化。

[En]

After receiving the request from the client, the server also needs to go through query cache, lexical syntax parsing and preprocessing, and query optimization.

2.1 查询缓存

如果我们执行同一条查询指令两次,第二次的响应时间会比第一次短吗?

[En]

If we execute the same query instruction twice, will the response time of the second time be shorter than that of the first time?

之前使用过Redis缓存工具的读者应该会有这个很自然的想法,MySQL收到查询请求之后应该先到缓存中查看一下,看一下之前是不是执行过这条指令。如果缓存命中,则直接返回结果;否则重新进行查询,然后加入缓存。

MySQL确实内部自带了一个缓存模块。

现在有一张500W行且没有添加索引的数据表,我执行以下命令两次,第二次会不会变得很快?

SELECT * FROM t_user WHERE user_name = '蝉沐风'

并不会!说明缓存没有生效,为什么?MySQL默认是关闭自身的缓存功能的,查看一下 query_cache_type变量设置。

mysql> show variables like 'query_cache_type';
+------------------------------+---------+
| Variable_name                | Value   |
+------------------------------+---------+
| query_cache_type             | OFF     |
+------------------------------+---------+

默认关闭就意味着不推荐,MySQL为什么不推荐用户使用自己的缓存功能呢?

  1. MySQL自带的缓存系统应用场景非常有限,它要求SQL语句必须一模一样,多一个空格,变一个大小写都被认为是两条不同的SQL语句
  2. 缓存失效非常频繁。只要一个表的数据有任何修改,针对该表的所有缓存都会失效。对于更新频繁的数据表而言,缓存命中率非常低!

所以缓存的功能还是交给专业的ORM框架(比如MyBatis默认开启一级缓存)或者独立的缓存服务Redis更加适合。

MySQL8.0已经彻底移除了缓存功能

2.2 解析器 & 预处理器(Parser & Preprocessor)

现在您已经跳过了缓存,接下来需要做什么?

[En]

Now that you’ve skipped caching, what do you need to do next?

如果我随便在客户端终端里输入一个字符串 chanmufeng,服务器返回了一个1064的错误

mysql> chanmufeng;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'chanmufeng' at line 1

服务器是怎么判断出我的输入是错误的呢?这就是MySQL的Parser解析器的作用了,它主要包含两步,分别是词法解析和语法分析。

2.2.1 词法解析

以下面的SQL语句为例

SELECT * FROM t_user WHERE user_name = '蝉沐风' AND age > 3;

分析器先会做”词法分析”,就是把一条完整的SQL语句打碎成一个个单词,比如一条简单的SQL语句,会打碎成8个符号,每个符号是什么类型,从哪里开始到哪里结束。

MySQL 从你输入的 SELECT这个关键字识别出来,这是一个查询语句。它也要把字符串 t_user
别成”表名 t_user”,把字符串 user_name识别成”列 user_name”。

2.2.2 语法分析

在词法分析之后,我们需要做语法分析。

[En]

After lexical parsing, we need to do grammatical analysis.

根据词法分析的结果,语法分析器会根据语法规则,判断你输入的这个 SQL 语句是否满足 MySQL 语法,比如单引号是否闭合,关键词拼写是否正确等。

解析器会根据SQL语句生成一个数据结构,这个数据结构我们成为解析树。

一条SQL查询语句是如何执行的?
我故意拼错了 SELECT关键字,MySQL报了语法错误,就是在语法分析这一步。
mysql> ELECT * FROM t_user WHERE user_name = '蝉沐风' AND age > 3;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ELECT * FROM t_user WHERE user_name = '蝉沐风'' at line 1

词法语法分析是一个非常基础的功能,Java 的编译器、百度搜索引擎如果要识别语句,必须也要有词法语法分析功能。

任何数据库的中间件,要解析 SQL完成路由功能,也必须要有词法和语法分析功能,比如 Mycat,Sharding-JDBC(用到了Druid Parser)等都是如此。在市面上也有很多的开源的词法解析的工具,比如 LEX,Yacc等。

2.2.3 预处理器

如果我们写了一条语法和词法都没有问题的SQL,但是字段名和表名却不存在,这个错误是在哪一个阶段爆出的呢?

词法解析和解析不可能知道数据库中有哪些表和字段。要了解这些信息,您需要在解析阶段使用另一个工具–预处理器。

[En]

It is impossible for lexical parsing and parsing to know what tables and fields are in the database. To know this information, you need another tool in the parsing phase– the preprocessor.

它检查生成的解析树以解析解析器无法解析的语义。例如,它检查表名和列名是否存在,并检查名称和别名以确保没有歧义。经过预处理后得到新的句法分析树。

[En]

It examines the generated parsing tree to resolve semantics that cannot be parsed by the parser. For example, it checks the existence of table and column names, and checks names and aliases to make sure there is no ambiguity. A new parsing tree is obtained after preprocessing.

本质上,解析和预处理是一个编译过程,涉及到词法解析、语法和语义分析,更多细节我们不会探究,感兴趣的读者可以看一下编译原理方面的书籍。

2.3 查询优化器(Optimizer)与查询执行计划

到了这一步,MySQL终于知道我们想查询的表和列以及相应的搜索条件了,是不是可以直接进行查询了?

还不行。MySQL作者担心我们写的SQL太垃圾,所以有设计出一个叫做 查询优化器的东东,辅助我们提高查询效率。

2.3.1 什么是查询优化器?

一条 SQL语句是不是只有一种执行方式?或者说数据库最终执行的 SQL是不是就是我们发送的 SQL?

不是。一条 SQL 语句是可以有很多种执行方式的,最终返回相同的结果,他们是等价的。

举个非常简单的例子,例如,您执行如下语句:

[En]

To give a very simple example, for example, you execute a statement like this:

SELECT * FROM t1, t2 WHERE t1.id = 10 AND t2.id = 20
  • 既可以先从表 t1 里面取出 id=10 的记录,再根据 id 值关联到表 t2,再判断 t2 里面 id 的值是否等于 20。
  • 也可以先从表 t2 里面取出 id=20 的记录,再根据 id 值关联到表 t1,再判断 t1 里面 id 的值是否等于 10。

这两种执行方法的逻辑结果是相同的,但执行效率会不同。如果有这么多行刑方法,如何获得呢?到底应该选哪一个来执行呢?根据什么标准来选择?

[En]

The logical results of the two execution methods are the same, but the efficiency of execution will be different. If there are so many execution methods, how can they be obtained? Which one should be chosen to execute in the end? According to what criteria to choose?

这个就是 MySQL的查询优化器的模块(Optimizer)的工作。

查询优化器的目的就是根据解析树生成不同的执行计划(Execution Plan),然后选择一种最优的执行计划,MySQL 里面使用的是基于开销(cost)的优化器,哪种执行计划开销最小,就用哪种。

2.3.2 优化器究竟做了什么?

举两个简单的例子∶

  1. 当我们对多张表进行关联查询的时候,以哪个表的数据作为基准表。
  2. 有多个索引可以使用的时候,选择哪个索引。

事实上,对于每一种数据库,优化器模块都是必不可少的,它们通过复杂的算法尽可能地优化查询效率。

[En]

In fact, for every kind of database, the optimizer module is essential, and they optimize query efficiency as much as possible through complex algorithms.

在细节方面,查询优化器主要在以下几个方面进行优化:

[En]

In terms of details, the query optimizer mainly optimizes in the following aspects:

  • 子查询优化
  • 等价谓词重写
  • 条件化简
  • 外连接消除
  • 嵌套连接消除
  • 连接消除
  • 语义优化

本文不会对优化的细节展开讲解,大家先对MySQL的整体架构有所了解就可以了,具体细节之后单独开篇介绍

但是优化器也不是万能的,如果SQL语句写得实在太垃圾,再牛的优化器也救不了你了。因此大家在编写SQL语句的时候还是要有意识地进行优化。

2.3.3 执行计划

优化后的结果是什么?优化器最终会将解析树转换为查询执行计划。

[En]

What do you get after optimization? The optimizer will eventually turn the parse tree into a query execution plan.

查询执行计划显示下一步如何执行查询,例如多个表关联查询、首先查询哪个表、执行查询时使用多个索引以及实际应该使用哪些索引。

[En]

The query execution plan shows how to execute the query next, such as multiple table association queries, which table to query first, multiple indexes to use when executing the query, and which indexes should actually be used.

MySQL提供了一个查看执行计划的工具。我们在 SQL语句前面加上 EXPLAIN就可以看到执行计划的信息。

mysql> EXPLAIN SELECT * FROM t_user WHERE user_name = '';
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+

如果要得到更加详细的信息,还可以用 FORMAT=JSON,或者开启 optimizer trace

mysql> EXPLAIN FORMAT=JSON SELECT * FROM t_user WHERE user_name = '';

文本不会带大家详细了解执行计划的每一个参数,内容很庞杂,大家先对MySQL的整体架构有所了解就可以了,具体细节之后单独开篇介绍

3. 存储引擎

经历千辛万苦,MySQL终于算出了最终的执行计划,然后就可以直接执行了吗?

好的。好的。现在还不是。

[En]

All right. all right. Still not yet.

我们知道表是由多行记录组成的,但这只是一个逻辑概念,或者就是它看起来的样子。

[En]

We know that a table is made up of rows of records, but this is just a logical concept, or just what it looks like.

3.1 什么是存储引擎

到底该把数据存储在什么位置,是内存还是磁盘?怎么从表里读取数据,以及怎么把数据写入具体的表中,这都是 存储引擎 负责的事情。

嗯,如果你看这个,你可能不知道什么是存储引擎。毕竟,存储引擎的名字听起来太神秘了。它的前身被称为表处理器。它是不是更平易近人?

[En]

Well, if you look at this, maybe you don’t know what a storage engine is. After all, the name of storage engine sounds too mysterious. Its predecessor is called table processor. Is it much more approachable?

3.2 为什么需要存储引擎

因为存储的需求不同。

试想一下:

  • 如果一个表需要很高的访问速度而不考虑持久化,那么最好的做法是将数据留在内存中吗?
    [En]

    if a table requires high access speed without considering persistence, is it best to keep the data in memory?*

  • 如果表用于归档历史数据而无需修改或索引,是否需要支持数据压缩?

    [En]

    if a table is used for archiving historical data without modification or indexing, is it necessary to support data compression?*

  • 如果在并发读写较多的业务中使用表,是否需要支持读写互不干扰,并保证数据的高一致性?

    [En]

    if a table is used in a business where there is a lot of concurrent reading and writing, is it necessary to support non-interference between reading and writing, and to ensure high data consistency?*

您应该理解为什么支持这么多存储引擎,因为一个存储引擎不能提供所有功能。

[En]

You should understand why so many storage engines are supported, because one storage engine cannot provide all the features.

存储引擎是计算机抽象的典型代表,它的功能就是接受上层指令,然后对表中数据进行读取和写入,而这些操作对上层完全是屏蔽的。你甚至可以查阅MySQL文档定义自己的存储引擎,只要对外实现同样的接口就可以了。

存储引擎就是MySQL对数据进行读写的插件而已,可以根据不同目的随意更换(插拔)

3.3 存储引擎怎么用

3.3.1 创建表的时候指定存储引擎

在创建表的时候可以指定当前表的存储引擎,如果没有指定,默认的存储引擎为 InnoDB,如果想显式指定存储引擎,可以这样

CREATE TABLE t_user_innodb (
  id int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (id)
) ENGINE=innodb DEFAULT CHARSET=utf8mb4;

3.3.2 修改表的存储引擎

ALTER TABLE 表名 ENGINE = 存储引擎名称;

3.4 存储引擎底层区别

下面我们分别创建3张设置了不同存储引擎的表, t_user_innodbt_user_myisamt_user_memory

一条SQL查询语句是如何执行的?
我们看一下不同存储引擎在底层存储方面的差异,首先找到MySQL的数据存储目录
mysql> show variables like 'datadir';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| datadir       | /var/lib/mysql/ |
+---------------+-----------------+

进入到目标目录之后,找到当前数据库对应的目录(MySQL会为一个数据库创建一个同名的目录),数据库中表的存储结构如下

一条SQL查询语句是如何执行的?
不同的存储引擎存放数据的方式不一样,产生的文件数量和格式也不一样,InnoDB文件包含2个,MEMORY文件包含1个,MYISAM文件包含3个。

3.5 常见存储引擎比较

首先我们查看一下当前MySQL服务器支持的存储引擎都有哪一些。

mysql> SHOW ENGINES;
+--------------------+---------+--------------+------+------------+
| Engine             | Support | Transactions | XA   | Savepoints |
+--------------------+---------+--------------+------+------------+
| InnoDB             | DEFAULT | YES          | YES  | YES        |
| MRG_MYISAM         | YES     | NO           | NO   | NO         |
| MEMORY             | YES     | NO           | NO   | NO         |
| BLACKHOLE          | YES     | NO           | NO   | NO         |
| MyISAM             | YES     | NO           | NO   | NO         |
| CSV                | YES     | NO           | NO   | NO         |
| ARCHIVE            | YES     | NO           | NO   | NO         |
| PERFORMANCE_SCHEMA | YES     | NO           | NO   | NO         |
| FEDERATED          | NO      | NULL         | NULL | NULL       |
+--------------------+---------+--------------+------+------------+

其中,

  • Support表示该存储引擎是否可用;
  • DEFAULT表示当前MySQL服务器默认的存储引擎;
  • Transactions表示该存储引擎是否支持事务;
  • XA表示该存储引擎是否支持分布式事务;
  • Savepoints表示该存储引擎是否支持事务的部分回滚。

3.5.1 MylSAM

应用范围比较小,表级锁定限制了读/写的性能,因此在Web和数据仓库配置中,通常用于只读或以读为主的工作。

特点:

  • 支持表级锁(表通过INSERT和UPDATE锁定),但不支持事务。
    [En]

    Table-level locks are supported (tables are locked by inserts and updates), but transactions are not supported.*

  • 拥有较高的插入(insert)和查询(select)速度;
  • 存储了表的行数(count速度更快)。

怎么快速向数据库插入100万条数据?

可以先用MylSAM插入数据,然后修改存储引擎为InnoDB。

3.5.2 InnoDB

MySQL 5.7及更新版中的默认存储引擎。InnoDB是一个事务安全(与ACID兼容)的MySQL 存储引擎,它具有提交、回滚和崩溃恢复功能来保护用户数据。InnoDB行级锁(不升级为更粗粒度的锁)和Oracle风格的一致非锁读提高了多用户并发性。InnoDB将用户数据存储在聚集索引中,以减少基于主键的常见查询的I/O。为了保持数据完整性,InnoDB还支持外键引用完整性约束。

特点:

  • 支持事务和外键,数据完整性和一致性更高
    [En]

    support transactions and foreign keys, so data integrity and consistency are higher*

  • 支持行级锁和表级锁
    [En]

    supports row-level locks and table-level locks*

  • 支持读写并发,写不阻塞读(MVCC);
  • 特殊的索引存放方式,可以减少IO,提升査询效率。

番外:InnoDB本来是InnobaseOy公司开发的,它和MySQL AB公司合作开源了InnoDB的代码。
但是没想到MySQL的竞争对手Oracle把InnobaseOy收购了。后来08年Sun公司(开发Java语言的Sun)收购了MySQL AB,09年Sun公司又被Oracle收购了,所以MySQL和 InnoDB又是一家了。
有人觉得MySQL越来越像Oracle,其实也是这个原因。

3.5.3 Memory

将所有数据存储在RAM中,以便快速访问。这个引擎以前被称为堆引擎。

特点:

  • 将数据放入内存,读写速度非常快,但如果数据库重启或崩溃,所有数据都会消失。
    [En]

    put the data in memory, the speed of reading and writing is very fast, but if the database is restarted or crashed, all the data will disappear.*

  • 只适合做临时表。

3.5.4 CSV

它的表实际上是带有逗号分隔值的文本文件。csv表允许以CSV格式导入或转储数据, 以便与读写相同格式的脚本和应用程序交换数据。因为CSV表没有索引,所以通常在正常操作期间将数据保存在InnoDB表中,只在导入或导出阶段使用csv表。

特点:

  • 不允许空行,不支持索引
    [En]

    empty lines are not allowed and indexes are not supported*

  • 格式通用,可直接编辑。它适用于不同数据库之间的导入和导出。
    [En]

    the format is universal and can be edited directly. It is suitable for import and export between different databases.*

3.5.5 Archive

专用和存档的空间被压缩,以存储和检索大量很少引用的信息。

[En]

Dedicated and archived, the space is compressed to store and retrieve a large amount of rarely referenced information.

特点:

  • 不支持索引;
  • 不支持update、delete。

3.6 如何选择存储引擎

  • 如果对数据一致性要求比较高,需要事务支持,可以选择InnoDB。
  • 如果数据查询多更新少,对查询性能要求比较高,可以选择MyISAM。
  • 如果需要一个用于查询的临时表,可以选择Memory。

如果所有的存储引擎都不能满足你的需求,并且技术能力足够,可以根据官网内部手册用C语言开发一个存储引擎:https://dev.mvsql.com/doc/internals/en/custom-engine.html

Original: https://www.cnblogs.com/chanmufeng/p/15848429.html
Author: 蝉沐风
Title: 一条SQL查询语句是如何执行的?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/507854/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • [VSCode] Todo Tree VSCode插件 待办事项树

    Todo Tree 一款待办事项插件 我们写程序的时候,难免会遇到一些情况需要标记或者搁置,在写代码的时候会用一些特殊的注释来表示不同的内容,使我们可以快速的定位我们注释的位置。 …

    数据库 2023年6月9日
    074
  • centos7 打包chrome离线安装包流程

    前提,centos可以连接外网 1、在目录 /etc/yum.repos.d/ 下新建文件 google-chrome.repo 文件中添加以下内容: 2、安装 yum-utils…

    数据库 2023年6月11日
    072
  • 巧用自定义注解,一行代码搞定审计日志

    任何一个软件系统,都不可避免的会碰到【 信息安全】这个词,尤其是对于刚入行的新手,比如我,我刚入行的时候,领导让我做一个数据报表导出功能,我就按照他的意思去做,至于谁有权限操作导出…

    数据库 2023年6月14日
    056
  • Linux_hadoop2.2.0伪分布式搭建安装

    1.1 开启网络,ifconfig指令查看ip 1.2 修改主机名为自己名字(hadoop)centos 7 连接:https://zhuanlan.zhihu.com/p/375…

    数据库 2023年6月11日
    096
  • Mysql面试总结

    转载自:https://www.cxyxiaowu.com/16302.html Q1:MySQL 的逻辑架构了解吗? 第一层是服务器层,主要提供连接处理、授权认证、安全等功能。 …

    数据库 2023年5月24日
    085
  • servlet映射路径匹配解析

    开头 servlet是javaweb用来处理请求和响应的重要对象,本文将从源码的角度分析tomcat内部是如何根据请求路径匹配得到处理请求的servlet的 假设有一个reques…

    数据库 2023年6月16日
    077
  • [Npoi]Npoi导入Excel, 转为Entity

    Npoi导入Excel其实只要读成DataTable就可以随意操作了, 比如转为Entity… By: 胖纸不争NetCore🐧群: 743336452 核心代码: p…

    数据库 2023年6月9日
    074
  • LeetCode 14. 最长公共前缀

    编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 “”。 示例 1: 输入:strs = [“flower&#8…

    数据库 2023年6月11日
    052
  • MyBatis(三)-动态SQL

    1、if 注意:test里面使用的参数,可以是mybatis的默认参数,也可以是实体属性名,但是不能是没有指定别名的参数名(尤其是单个参数,也必须起别名,否则异常); 单独使用if…

    数据库 2023年6月16日
    079
  • Centos7环境使用Mysql离线安装包安装Mysql5.7

    服务器环境:centos7 x64 需要安装:mysql5.7+ 1)检查mysql组合用户是否存在 2)若不存在,则创建mysql组和用户 对于版本选择,您可以选择以下两种方式:…

    数据库 2023年5月24日
    068
  • 配置文件动态刷新

    1. 背景 2. 相关知识储备 思路一 : 民科 mtime 文件最后修改时间 思路二: 科班 操作系统通知特性, 例如 linux 的 inotify 3. 相关代码设计 总结 …

    数据库 2023年6月9日
    073
  • 做自动化测试选择Python还是Java?

    你好,我是测试蔡坨坨。 今天,我们来聊一聊测试人员想要进阶,想要做自动化测试,甚至测试开发,如何选择编程语言。 自动化测试,这几年行业内的热词,也是测试人员进阶的必备技能,更是软件…

    数据库 2023年6月11日
    089
  • 【StoneDB技术解析】验证相关数据包是否需要解压缩

    在StoneDB中,数据包分为以下几类: 通过对数据包的划分,知识网格技术过滤掉不相关的数据包,读取相关的数据包和可疑的数据包。其中相关的数据包不需要解压缩,只读取元数据,不会发生…

    数据库 2023年5月24日
    067
  • 创建一个Django项目总结

    2022-09-25 首先,要安装好虚拟环境,之后要切换到虚拟环境中,使用的命令 之后,创建一个Django项目使用的命令: 进入到该项目的目录下,创建一个子应用,使用的命令: 其…

    数据库 2023年6月14日
    088
  • Redis-缓存和数据库一致性问题

    三种策略 Cache Aside 只读缓存模式,即读操作命中缓存直接返回,未命中从后端数据库加载到缓存再返回。写操作直接更新数据库,并删除缓存。👍一切以后端数据库为准,最常用的方式…

    数据库 2023年6月11日
    064
  • 一条SQL更新语句是如何执行的

    文章首发于公众号「蝉沐风」,认真写好每一篇文章,欢迎大家关注交流 这是图解MySQL的第2篇文章,这篇文章会通过 一条SQL更新语句的执行流程让大家清楚地明白: 什么是InnoDB…

    数据库 2023年5月24日
    094
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球