一句简单的SQL查询语句的背后...

时间:2022-09-15 15:11:09

当我们在SQL Server Management Studio的查询里面输入: SELECT * FROM t1 WHERE c1=2;

背后发生了什么?数据库怎么去执行查询的?知其然不知其所以然。

 

1.         Query Parsing, Synatax Error Check, and Authorization: Query Processer check the user is authorized to run the query;(查询处理器首先进行语法解析,语法检查,并检查授权。如果没有获得授权执行相关的操作,或者语法错误,将报错。)

2.         Query Re-writingSemantic Optimization (查询处理器重新写SQL语句并做相应的优化)。

例如:SELECT Emp.name, Emp.salary
                         FROM Emp, Dept
                            WHERE Emp.deptno = Dept.dno

              Join是多余的,查询处理器会重写该语句并删除到表DeptJoin

3.         Compile the SQL into internal query Plan; (编译SQL到内部查询计划)

       数据库会选择最佳的方法来计算结果集。例如进行全表扫描,或是使用索引(pairs of key and location类似书的目录)。数据库会比较它们的成本,并形成内部执行计划。数据库内部负责计算选择最佳执行计划的组件叫优化器(Optimizer)。

4.         The query plan is handled by plan executor, which consists of many operators, e.g. joining, sorting, grouping... (查询计划被计划执行器执行。计划执行器包含很多操作者,例如执行Join, Sort, Group等,还要有访问方法管理器来决定存取哪些数据页或索引页,或是直接缓存命中,这些有缓冲管理器负责... ...)

5.         Transaction manager is started as well to ensure the ACID of operations. (事务管理器同时启动来保证原子操作的并发一致性, 其他例如锁管理器、索引管理器、行管理器、页面文件管理器、缓冲管理器、日志管理器和等也会执行,而不是有查询执行器一人包办所有。)

 

执行如下语句:SELECT * FROM t1 WHERE c1=2的简单过程:

 

1.        扫描t1表,如果是开始则取第一条记录,否则取下一条记录;如果读到表的最后一条记录了那么跳到第4步。

2.        检查记录是否满足WHERE条件;是则进入第3步,否则回到第1步。

3.        把记录加到结果集。

4.        返回结果集给客户端。

 

 

如果表有索引,优化器可能比较全表扫描和索引,并可能决定执行计划为扫描索引。则步骤类似,不过第1步变成:

扫描索引(Clustered or no-clustered)并定位到记录。

 

例如:

 SELECT * FROM Customers WHERE contactID IN

(SELECT contactID FROM Contacts WHERE contactID=86)

ORDER BY CustomerName DESC;

 

增加的步骤有:

1.        在表[Contacts]中扫描索引并定位记录。

2.        在表[Customers]中扫描索引并定位记录。

3.        Hash match (inner join),哈希匹配,连接。

4.        Sort,排序

 

有关Join

SQL Server employs three types of join operations:

  • Nested loops joins
  • Merge joins
  • Hash joins

 

  1. 如果Join的输入很小,例如小于10行,然后其他的Join输入很大并且索引在其列上,则Nested loops joins是最快的。(原因参考Understanding Nested Loops Joins
  2. 如果两个Join输入都不小,但在索引列上排序(例如是在扫描排序的索引后获得的 scanning sorted indexes),则Merge joins是最快的。(原因参考Understanding Merge Joins
  3. Hash joins可以有效的处理大量的、没有排序的、没有索引的输入。尤其对复杂查询的中间结果处理很有效。(更多参考Understanding Hash Joins

 

这些只是一些简单的过程,其实数据库内部执行过程是相当复杂的。虽然我们不是数据库开发人员,但了解上下游的知识是必须的,能够有助于我们的开发和应用。技术不仅要知道怎么用,而且要知道为什么,不能知其然不知其所以然。最后附上一张数据库内部简单结构图供有兴趣的人参考。

 

一句简单的SQL查询语句的背后...