一条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)

大家都在看

  • 事务

    事务 *事务的简介 事务是一组操作的合集,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体,一起向系统提交或撤销操作请求,这些操作只有同时成功、同时失败; 事务的操作 查…

    数据库 2023年6月16日
    0143
  • 安装多个Jdk

    安装 官方下载地址 目录结构: 配置 PATH 修改 注意:此处的操作可能会有其他未知的问题,最好还是理解window的命令查找机制,然后还是需要根据具体问题具体分析解决。 测试 …

    数据库 2023年6月11日
    0130
  • mysql8使用tmpfs内存磁盘当内存数据库的配置方法

    内存关系数据库没有找到开源好用的,很多都是商用。虽然mysql有memory引擎,但写是整体锁表,没法用。 一直想将mysql放入内存中,搜索n次资料,没找到合适的,可能之前思路不…

    数据库 2023年6月14日
    0142
  • MySQL 安全管理

    权限表 MySQL 服务器通过权限表来控制用户对数据库的访问,由 mysql_install_db 脚本初始化,MySQL 会根据这些权限表的内容为每个用户赋予相应的权限 user…

    数据库 2023年5月24日
    0127
  • 2022-8-10 JAVA的反射机制

    反射机制 AVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方…

    数据库 2023年6月14日
    0128
  • 滑动窗口

    滑动窗口,记录左边界,通过map避免字符重复。 class Solution { public int lengthOfLongestSubstring(String s) { i…

    数据库 2023年6月11日
    0106
  • Mysql_范式入门

    MySQL 三大范式 为什么需要数据规范化 信息重复 更新异常 插入异常 无法正常显示信息 删除异常 丢失有效的信息 设计关系型数据库时,遵从不同的规范要求,设计出合理的关系型数据…

    数据库 2023年6月11日
    0133
  • 使用 yum 在 CentOS7 上安装 MySQL8

    时间:2022-07-13安装版本:MySQL-community-8.0.29 0. 删除MariaDB 在CentOS 7中默认有安装MariaDB,这个是MySQL的分支,通…

    数据库 2023年6月16日
    0132
  • [LeetCode]13. 罗马数字转整数

    罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做…

    数据库 2023年6月9日
    0177
  • day04-3服务器推送新闻

    多用户即时通讯系统04 4.编码实现03 4.7功能实现-服务器推送消息功能实现 4.7.1思路分析 服务器推送新闻,本质其实就是群发消息 在服务器启动一个独立线程,专门负责推送新…

    数据库 2023年6月11日
    094
  • day43-反射02

    Java反射02 2.Class类 2.1基本介绍 Class类也是类,因此也继承Object类 Class类对象不是new出来的,而是系统创建的 对于某个类的Class类对象,在…

    数据库 2023年6月11日
    0132
  • MySQL提示sql_mode=only_full_group_by解决办法

    MySQL异常sql_mode=only_full_group_by 原因:在MySQL 5.7后MySQL默认开启了SQL_MODE严格模式,对数据进行严格校验。会报sql_mo…

    数据库 2023年6月14日
    0125
  • 高可用 | Xenon 实现 MySQL 高可用架构 常用操作篇

    原创:知数堂 上一篇文章,我们详细介绍了 Xenon 实现 MySQL 高可用架构的部署过程。接下来本篇将介绍 Xenon 的常用操作,帮助大家在完成环境搭建之后,能把 Xenon…

    数据库 2023年5月24日
    0137
  • mysql视图,索引

    一、视图 View 视图是一个 虚拟表,是sql语句的查询结果,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据,在使用视图时动态生成。视图的数据变化会影响到基…

    数据库 2023年6月9日
    092
  • 系列文章分类汇总

    尤娜系列 从前,有一个简单的通道系统叫尤娜…… 尤娜系统的第一次飞行中换引擎的架构垂直拆分改造 四种常用的微服务架构拆分方式 尤娜,我去面试了 专业课回顾 …

    数据库 2023年6月6日
    085
  • Redisson

    ​ Redisson是架设在Redis基础上的一个Java驻内存数据网格(In-Memory Data Grid)。充分的利用了Redis键值数据库提供的一系列优势,基于Java实…

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