今天来当一下数据库,看一下sql到底在里面如何执行的?
一、引子
不管是开发,还是运维,亦或者是产品。
多多少少会写sql,只不过有的人写得多,有的人写得少罢了。
但是你有想过,在数据库中,sql 到底是什么执行的吗?
最常见的两个数据库,Oracle和Mysql,今天就来看看执行流程。
开始之前抛出三个问题:
- Oracle 中的 SQL 是如何执行的,什么是硬解析和软解析;
- MySQL 中的 SQL 是如何执行的,MySQL 的体系结构又是怎样的;
- 什么是存储引擎,MySQL 的存储引擎都有哪些?
这也算是常见的Java面试题了。
ok,开干。
二、开干
让我们来看下第一个问题。
Oracle数据库,众所周知是付费的,小型企业基本上不用,如果你在开发中使用,我盲猜一手,你是不是尊贵的浦发银行的外包人员,又亦或者是xxx单位呢?
ok,开个玩笑,正式起航。
问题一:Oracle 中的 SQL 是如何执行的,什么是硬解析和软解析?
在Oracle中,SQL的执行过程可以简单分成以下的四个步骤:
-
解析(Parsing):当一个SQL语句被提交给Oracle数据库时,首先进行解析阶段。解析器会对SQL语句进行语法检查、语义检查,并生成解析树(Parse Tree)和内部数据结构。解析的结果会被用于后续的优化和执行阶段。
-
优化(Optimization):在解析完成后,优化器会根据解析树、表和索引的统计信息等,选择最佳的执行计划。执行计划是一个操作指令序列,它描述了数据库引擎在执行SQL语句时的具体操作方式,包括表的访问路径、连接方法、索引使用等。优化器会根据代价估算器评估不同执行计划的代价,并选择代价最小的执行计划。
-
执行(Execution):一旦优化器选择了执行计划,数据库引擎会按照执行计划的指令序列执行SQL语句。这包括打开表、获取锁、读取数据、执行计算等操作。数据库引擎会利用缓冲区高速缓存(Buffer Cache)中的数据来加速访问,并在必要时执行物理I/O操作。
-
提交(Commit):如果SQL语句是一个事务的一部分,在执行过程中可能会修改数据库中的数据。一旦SQL语句执行完毕,数据库引擎会等待事务的其他操作,然后根据事务的隔离级别,决定是否将修改的数据提交到数据库中。
优化器的作用是选择最佳的执行计划,以提高SQL语句的执行性能。
执行计划的质量对SQL语句的性能至关重要,因此在设计数据库结构、编写SQL语句和管理统计信息时,都需要考虑优化器的影响。
是不是看的难受,其实我也懒得看。
当执行一个SQL语句时,来看下步骤是咋样的:
-
解析(Parsing):
- SQL语句:SELECT * FROM employees WHERE department_id = 10;
- 解析器对SQL语句进行语法检查和语义检查,生成解析树(Parse Tree)。
- 解析树示例:
SELECT | └─── * FROM | └─── employees WHERE | └─── department_id = 10
-
优化(Optimization):
- 优化器根据解析树、表和索引的统计信息等,选择最佳的执行计划。
- 假设表"employees"有一个名为"department_id"的索引。
- 优化器决定使用索引来加速查询,生成执行计划。
- 执行计划示例:
OPERATION OPTIONS OBJECT_NAME ------------------ --------------- ------------- SELECT STATEMENT | └─── TABLE ACCESS FULL employees FILTER | └─── INDEX RANGE SCAN (department_id)
-
执行(Execution):
- 数据库引擎按照执行计划的指令序列执行SQL语句。
- 首先,打开表"employees",获取相关数据。
- 然后,对表中的每一行应用WHERE条件进行过滤,保留符合条件的行。
- 最后,返回符合条件的结果集。
- 执行结果:
employee_id first_name last_name department_id ----------- ---------- --------- ------------- 101 John Doe 10 102 Jane Smith 10 103 Mike Johnson 10
-
提交(Commit):
- 如果SQL语句是一个事务的一部分,在执行过程中可能会修改数据库中的数据。
- 一旦SQL语句执行完毕,数据库引擎等待事务的其他操作。
- 根据事务的隔离级别和其他操作的结果,决定是否将修改的数据提交到数据库中。
这只是一个简单的demo,实际开发环境中会涉及到表的大小,索引的使用情况,系统负载等等
而且
sql的执行过程还涉及到锁管理、并发控制、日志记录等其他的细节…这些东西以后再说。
说一下软硬解析
软解析和硬解析都发生在解析(Parsing)阶段中。
软解析(Soft Parsing)是在第一次执行SQL语句时进行的解析过程。
当一个SQL语句首次被提交给Oracle数据库时,解析器会对SQL语句进行完整的解析过程,包括语法检查、语义检查、查询解析等,然后生成解析树和内部数据结构。
如果该SQL语句已经在共享池中存在对应的解析结果(即共享池中有缓存),则可以直接使用共享池中的解析结果,跳过软解析的过程,这称为共享池命中(Shared Pool Hit)。
硬解析(Hard Parsing)发生在以下情况:
- 当SQL语句首次执行时,没有在共享池中找到对应的解析结果,需要进行完整的解析过程,生成解析树和内部数据结构。
- 当SQL语句发生变化,如语法结构有所调整、绑定变量的值发生变化等,无法重复使用之前的解析结果时,需要进行硬解析。
优化器在解析完成后使用解析树和其他统计信息来进行优化决策,选择最佳的执行计划。因此,软解析和硬解析是解析阶段的一部分,它们发生在优化和执行阶段之前。
比如:
-- 第一次执行SQL语句,进行软解析和硬解析
SELECT * FROM employees WHERE department_id = 10;
-- 再次执行SQL语句,只进行软解析
SELECT * FROM employees WHERE department_id = 10;
在以上代码中,首次执行SQL语句 SELECT * FROM employees WHERE department_id = 10;
时,会进行软解析和硬解析的过程。
解析器会对SQL语句进行语法检查、语义检查,并生成解析树和内部数据结构。因为是首次执行,所以需要进行完整的解析过程,包括硬解析。解析器会生成解析树和执行计划,以供后续的优化和执行。
在第二次执行相同的SQL语句时,因为之前的解析结果已经存在于共享池中,解析器可以直接从共享池中获取解析结果,跳过硬解析过程。这称为共享池命中,只进行软解析的过程。共享池的存在可以减少重复解析的开销,提高查询性能。
插一嘴共享池的概念:
- 存储和管理共享的内部数据结构和SQL语句解析结果,以提高系统性能和减少重复解析的开销。
问题二:MySQL 中的 SQL 是如何执行的,MySQL 的体系结构又是怎样的?
在MySQL中,SQL的执行过程可以分为以下5步骤:
-
语法解析(Parsing):当一个SQL语句被提交给MySQL数据库时,首先进行语法解析。解析器会对SQL语句进行语法检查和语义检查,确保语句的正确性。如果发现语法错误,解析器将报告错误信息。如果语法正确,解析器会生成解析树。
-
查询优化(Query Optimization):在解析完成后,MySQL会使用查询优化器对解析树进行优化。查询优化器会考虑执行计划中的多种可能性,选择最佳的执行计划。它会根据表的大小、索引的使用情况、查询的复杂性等因素进行评估,并尽量选择性能最好的执行计划。
-
执行计划生成(Execution Plan Generation):一旦查询优化器选择了执行计划,MySQL会生成执行计划,即执行SQL语句的具体操作方式。执行计划描述了表的访问路径、连接方法、索引使用等信息。
-
执行(Execution):MySQL根据生成的执行计划执行SQL语句。这包括打开表、获取锁、读取数据、执行计算等操作。MySQL会利用缓冲池(Buffer Pool)中的数据来加速访问,并在必要时执行物理I/O操作。
-
返回结果(Result Return):一旦SQL语句执行完毕,MySQL将返回执行结果给客户端。结果可以是一个结果集、影响的行数或其他执行信息,具体取决于SQL语句的类型。
来,继续看步骤:
-
语法解析(Parsing):
- SQL语句:SELECT * FROM employees WHERE department_id = 10;
- 解析器对SQL语句进行语法检查和语义检查,确保语句的正确性。
- 如果语法错误,解析器会报告错误信息。
- 如果语法正确,解析器生成解析树(Parse Tree)。
- 解析树示例:
SELECT | └─── * FROM | └─── employees WHERE | └─── department_id = 10
-
查询优化(Query Optimization):
- 查询优化器考虑多种可能的执行计划,选择最佳的执行计划。
- 假设表"employees"有一个名为"department_id"的索引。
- 优化器决定使用索引来加速查询,生成执行计划。
- 执行计划示例:
ID SELECT_TYPE TABLE TYPE POSSIBLE_KEYS KEY KEY_LEN REF ROWS FILTERED -- ----------- --------- ---- ------------- -------- ------- --- ---- --------- 1 SIMPLE employees ref department_id key_dept 4 const 3 100.00
-
执行计划生成(Execution Plan Generation):
- 执行计划描述了SQL语句的具体操作方式,包括表的访问路径、连接方法、索引使用等信息。
- MySQL生成执行计划根据优化器的选择和表的结构。
- 执行计划示例:
ID SELECT_TYPE TABLE TYPE POSSIBLE_KEYS KEY KEY_LEN REF ROWS FILTERED -- ----------- --------- ---- ------------- -------- ------- --- ---- --------- 1 SIMPLE employees ref department_id key_dept 4 const 3 100.00
-
执行(Execution):
- 数据库引擎按照执行计划的指令序列执行SQL语句。
- 首先,通过索引"key_dept"找到department_id=10的行的引用(REF)。
- 然后,返回符合条件的结果集。
- 执行结果:
employee_id first_name last_name department_id ----------- ---------- --------- ------------- 101 John Doe 10 102 Jane Smith 10 103 Mike Johnson 10
-
返回结果(Result Return):
- 一旦SQL语句执行完毕,数据库引擎将返回执行结果给客户端。
- 结果可以是一个结果集、影响的行数或其他执行信息,具体取决于SQL语句的类型。
说一下mysql的体系结构:
MySQL的体系结构是基于C/S模型的,它包含多个组件和模块,每个模块负责不同的功能。下面是一些组件:
-
客户端(Client):
- 客户端是与MySQL服务器进行通信的应用程序或工具,如命令行客户端、图形界面工具或Web应用程序。
- 客户端通过连接到MySQL服务器发送SQL语句或其他指令,并接收和处理来自服务器的响应。
-
连接管理器(Connection Manager):
- 连接管理器负责处理客户端与MySQL服务器之间的连接。
- 它接受客户端的连接请求并将其分配给适当的后端线程或进程进行处理。
- 连接管理器还负责管理连接池,以提高连接的复用和性能。
-
查询解析器和优化器(Query Parser and Optimizer):
- 查询解析器负责解析客户端发送的SQL语句,检查其语法和语义的正确性,并生成解析树。
- 查询优化器根据解析树和数据库统计信息来生成最佳的执行计划。
- 优化器考虑索引、表的大小、查询复杂性等因素,以提高查询性能。
-
执行引擎(Execution Engine):
- 执行引擎根据查询优化器生成的执行计划执行SQL语句。
- 它负责读取数据、处理连接、执行过滤和排序等操作。
- 执行引擎还负责对表的访问、锁定管理、事务处理和数据缓存等操作。
-
存储引擎(Storage Engine):
- 存储引擎负责实际的数据存储和检索。
- MySQL支持多个存储引擎,如InnoDB、MyISAM、Memory等。
- 不同的存储引擎具有不同的特性、性能和适用场景。
-
日志管理(Logging):
- MySQL使用日志来记录对数据库的变更操作,以便在需要时进行恢复和回滚。
- 主要的日志类型包括二进制日志、错误日志、查询日志和慢查询日志。
-
缓存管理(Caching):
- MySQL使用缓存来提高查询性能和响应速度。
- 缓存包括查询缓存、表缓存和缓冲池(Buffer Pool)等。
-
数据字典(Data Dictionary):
- 数据字典存储了数据库的元数据信息,如表结构、索引、约束等。
- 它记录了数据库的对象定义和关系。
问题三:什么是存储引擎,MySQL 的存储引擎都有哪些?
存储引擎(Storage Engine)是MySQL数据库中负责实际数据存储和检索的组件。
它定义了数据如何被组织、存储和访问。MySQL支持多个存储引擎,每个存储引擎具有不同的特性、性能和适用场景。以下是MySQL中常见的存储引擎:
-
InnoDB:
- InnoDB是MySQL的默认存储引擎,也是最常用的存储引擎。
- 它提供了ACID事务支持,支持行级锁定,适用于高并发的读写操作。
- InnoDB支持外键约束、崩溃恢复和故障容错机制。
-
MyISAM:
- MyISAM是MySQL的另一个常见存储引擎。
- 它不支持事务和行级锁定,适用于读操作频繁、写操作较少的场景。
- MyISAM对于表锁定的支持较好,适合于静态数据和只读应用。
-
Memory(或者称为 Heap):
- Memory存储引擎将数据存储在内存中,适用于临时表、缓存和其他对速度要求较高的应用。
- 它不支持持久性,当MySQL服务重启时,存储在Memory引擎中的数据将丢失。
-
NDB Cluster(也称为MySQL Cluster):
- NDB Cluster是一个分布式存储引擎,适用于高可用性和高可扩展性的应用。
- 它将数据分片存储在多台服务器上,提供了数据的冗余备份和自动故障恢复机制。
除了上述常见的存储引擎外,MySQL还支持其他存储引擎,如Archive、CSV、Blackhole等。
这里在插一嘴:
- Oracle没有存储引擎这个概念。他自己本身有一套统一的存储结构和架构,称之为Oracle存储结构。而且在Oracle中,数据是以表空间的形式进行存储和管理的。