数据库查询优化技术

Posted 思考的犀牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库查询优化技术相关的知识,希望对你有一定的参考价值。

1. 什么是数据库查询优化技术

1.1 查询复用

1.1.1 查询重用是指尽可能利用先前的执行结果,以达到节约查询计算全过程的时间并减少资源消耗的目的。

1.1.2 目前查询重用技术主要集中在两个方面:

  1. 查询结果的重用。在缓存区中分配一块缓冲块,存放该SQL 语句文本和最后的结果集,当同样的SQL输入时,直接把结果返回。查询结果的重用技术节约了查询计划生成时间,减少了查询执行全过程的资源消耗;

  2. 查询计划的重用。缓存一条查询语句的执行计划及其相应语法树结构。查询计划的重用技术减少了查询计划生成的时间和资源消耗。

查询重用技术利弊:

  1. 弊端:结果集很大会消耗很大的内存资源,同样的SQL不同用户应该获取的结果集可能不同;

  2. 利端:节约了CPU和IO消耗。在实际使用的过程中,趋利避害,根据实际情况选用;

1.2 查询重写规则

1.2.1 查询重写:

是查询语句的一种等价转换,即对于任何相关模式的任意状态都会产生相同的结果(相同的关系替代两个表达式中相应的关系,所得到的结果是相同的)。

1.2.2 查询重写的两个目标:

    1. 将查询转换为等价的效率更高的形式,例如将效率低的谓词转换为效率高的谓词、消除重复条件等。

    2. 尽量将查询重写为等价、简单且不受表顺序限制的形式,为物理查询优化阶段提供更多的选择,如视图的重写、子查询的合并转换等。

1.2.3 查询重写的依据:

查询重写的依据,是关系代数,请参看:

    1.关系代数的等价变换规则对查询重写提供了理论上的支持。

    2.查询重写后,查询优化器可能生成多个连接路径,可以从候选者中择优。

1.2.4 查询优化技术类型:

    1.语法级。查询语言层的优化,基于语法进行优化。

    2.代数级。查询使用形式逻辑进行优化,运用关系代数的原理进行优化。

    3.语义级。根据完整性约束,对查询语句进行语义理解,推知一些可优化的操作。

    4.物理级。物理优化技术,基于代价估算模型,比较得出各种执行方式中代价最小的。

查询重写是基于语法级、代数级、语义级的优化,可以统一归属到逻辑优化的范畴:基于代价估算模型是物理层面的优化,是从连接路径中选择代价最小的路径的过程。

1.2.5 查询优化重写思路:

  1. 将过程性查询转换为描述性的查询,如视图重写。

  2. 将复杂的查询(如嵌套子查询、外连接消除、嵌套连接消除)尽可能转换为多表连接查询。

  3. 将效率低的谓词转换为等价的效率高的谓词(如等价谓词重写)。

1.2.6 查询优化重写思路:

  1. 利用等式和不等式的性质,简化WHERE、HAVING和ON条件。

  2. 如何改进现有查询重写规则的效率,如何发现更多更有效的重写规则,是查询优化的研究内容之一。

  3. 常见的查询重写技术类型,每一类都有自己的规则,这些规则没有确定的、统一的规律,但重写的核心一定是“等价转换”,只有等价才能转换,这是需要特别强调的。

1.2 查询优化算法

1.2.1 什么是查询优化算法?

查询优化,求解给定查询语句的高效执行计划的过程。这样的过程,包括了多种子问题求解。不同的子问题,对应了不同的解决方法,即算法。

1.2.2 什么是查询计划?

查询计划,也称为查询树,它由一系列内部的操作符组成,这些操作符按一定的运算关系构成查询的一个执行方案。

简单说,就是表A和表B先连接得到中间结果,然后再和另外的表C连接得到新的中间方式,直至所有表都被连接完毕(连接操作就是操作符,这个示例有两个连接操作符。A连接B连接C、C连接B连接A就是两种不同的执行方案,即是两个不同的执行计划,查询优化要选出最高效的一个执行方案)。

1.2.3 查询计划的形式:

查询计划,从形式上看,是一颗二叉树,树叶是每个单表对象;

两个树叶的父结点是一个连接操作符(如左外连接操作符,A left-out join B)连接后的中间结果(另外还有一些其他结点如排序操作等也可以作为中间结果)这个结果是一个临时“关系”,这样直至根结点。

1.2.4 查询计划,二叉树上的不同结点:

1.2.4.1 单表结点:

考虑单表的数据获取方式,是直接通过IO获得数据,还是通过索引获取数据,或者是通过索引定位数据的位置后再经过IO到数据块中获取数据。

这是一个从物理存储到内存解析成逻辑字段的过程,即符合冯·诺依曼体系结构的的要求(外存数据读入内存才能被处理)。

1.2.4.2 两表结点:

考虑两表以何种方式连接、代价有多大、连接路径有哪些等。表示的是内存中的元组,怎么进行元组间的连接。此时,元组通常已经存在于内存,直接使用即可。这是一个完成用户语义的逻辑操作,但是只是局部操作,只涉及两个具体的关系。完成用户全部语义(用户连接的语义),需要配合多表的连接顺序的操作。

不同的连接算法导致的连接效率不同,如数据少时可使用Hash连接,数据量大可使用嵌套连接,数据如果有序可使用归并连接或先排序后使用归并连接等。

1.2.4.3 多表结点:

考虑多表连接顺序如何构成代价最少的“执行计划”。决定是AB先连接还是BC先连接,这是一个比较花费大小的运算。如果太多的连接方式被判断,也会导致效率问题。多个关系采用不同次序进行连接,花费的CPU资源、内存资源差异可能较大。

许多数据库采用左深树、右深树、紧密树三种方式或其中一部分对多表进行连接得到多种连接路径。

1.2.5 生成最优查询计划的策略:

  1. 基于规则优化

根据经验或一些已经探知或被证明有效的方式,定义为“规则”(如根据关系代数得知的规则、根据经验得知的规则等),用这些规则化简查询计划生成过程中符合可被化简的操作,使用启发式规则排除一些明显不好的存取路径,这就是基于规则的优化。

  2. 基于代价优化

根据一个代价评估模型,在生成查询计划的过程中,计算每条存取路径(存取路径主要包括上述三个“关系结点”)的花费,然后选择代价最小的作为子路径,这样直至所有表连接完毕得到一个完整的路径。

主流数据库都采用了基于代价策略进行优化的技术。

主流数据库对于基于规则和基于代价的技术,都在使用!

基于规则优化具有操作简单且能快速确定连接方式的优点,但这种方法只是排除了一部分不好的可能,所以得到的结果未必是最好的;

基于代价优化,是对各种可能的情况进行量化比较,从而可以得到花费最小的情况,但如果组合情况比较多则花费的判断时间就会很多;

查询优化器的实现,多是两种优化策略组合使用,如mysql和PostgreSQL就采取了基于规则和代价估算的查询优化策略。

1.3 并行查询优化

1.3.1 查询优化为什么要并行?

传统单机数据库系统中,给定一个查询(Query),查询优化算法只需找到查询的一个具有最小执行花费的执行计划,这样的计划必定具有最快的响应时间。

在并行数据库系统中,查询优化的目标是寻找具有最小响应时间的查询执行计划,这需要把查询工作分解为一些可以并行运行的子工作。一些商业数据库提供了并行查询的功能,用以优化查询执行操作。

1.3.2 查询优化并行的条件:

一个查询能否并行执行,取决于多种因素:

  1. 系统中的可用资源(如内存、高速缓存中的数据量等)。

  2. CPU的数目。

  3. 运算中的特定代数运算符。

如A、B、C、D四个表进行连接,每个表的单表扫描可以并行进行;在生成四个表连接的查询计划过程中,可选择A和B连接的同时C和D进行连接,这样连接操作能并行运行。不同商业数据库,对查询并行的实现也不尽相同。

1.3.3 查询优化并行的条件:

在同一个SQL内,查询并行可以分为:

  1. 操作内并行。将同一操作如单表扫描操作、两表连接操作、排序操作等分解成多个独立的子操作,由不同的CPU同时执行。

  2. 操作间并行。一条SQL查询语句可以分解成多个子操作,由多个CPU执行。

1.3.4 在分布式数据库系统中, 查询策略优化是查询优化的重点。

主要是数据传输策略,A、B两结点的数据进行连接,是A结点数据传输到B结点或是从B到A或是先各自进行过滤然后再传输等)和局部处理优化(传统的单结点数据库的查询优化技术)。

1.4 分布式查询优化

在查询优化策略中,数据的通信开销是优化算法考虑的主要因素。分布式查询优化以减少传输的次数和数据量作为查询优化的目标。

分布式数据库系统中的代价估算模型,除了考虑CPU代价和I/O代价外,还要考虑通过网络在结点间传输数据的代价。这是分布式并行查询优化技术与传统单结点数据库系统最大不同之处。

在分布式数据库系统中,代价估算模型为:

总代价 = I/O代价 + CPU代价 + 通信代价

2. 什么是逻辑查询优化

总得来说:关系理论+查询重写+启发式规则=逻辑查询优化

2.1 查询的基本操作

2.1.1 选择操作:

对应的是限制条件(格式类似“field  consant”,field表示列对象,op是操作符如“=”、“>”等)。

优化方式是选择操作下推,目的是尽量减少连接操作前的元组数,使得中间临时关系尽量少(元组数少,连接得到的元组数就少),这样可能减少IO和CPU的消耗、节约内存空间。

2.1.2 投影操作:

对应的SELECT查询的目的列对象。优化方式是投影操作下推。

目的是尽量减少连接操作前的列数,使得中间临时关系尽量小(特别注意差别:选择操作是使元组的个数“尽量少”,投影操作是使一条元组“尽量小”),这样虽然不能减少IO(多数数据库存储方式是行存储,元组是读取的最基本单位,所以要想操作列则必须读取一行数据),但可以各减少连接后的中间关系的元组大小,节约内存空间。

2.1.3 连接操作

对应的是连接条件(格式类似“field_1  field_2”,field_1和field_2表示不同表上的列对象,op是操作符如“=”、“>”等),表示两个表连接的条件。

连接操作涉及两个子问题:

  1. 多表连接中每个表被连接的顺序决定着效率

    如果一个查询语句只有一个表,则这样的语句很简单;但如果有多个表,则会涉及表之间以什么样的顺序连接最高效(如A、B、C三表连接,如果ABC、ACB、BCA等连接后的结果集一样,则哪种连接次序的效率最高,是需要考虑的问题)。

  2. 多表连接每个表被连接的顺序被用户语义决定

    查询语句多表连接有着不同的语义(如是笛卡儿集、内连接、还是外连接中的左外连接等),这决定着表之间的前后连接次序是不能随意更换的,否则,结果集中数据是不同的。因此,表的前后连接次序是不能随意交换的。

2.1.4 查询的2种类型:

根据SQL语句的形式特点,还可以做如下区分:

  1. 针对SPJ的查询优化

基于选择、投影、连接三种基本操作相结合的查询。

  2. 针对非SPJ的查询优化

在SPJ的基础上存在GROUPBY操作的查询,这是一种较为复杂的查询。所以,针对SPJ和非SPJ的查询优化,其实是对以上多种操作的优化。“选择”和“投影”操作,可以在关系代数规则的指导下进行优化。表连接,需要多表连接的相关算法完成优化。其他操作的优化多是基于索引和代价估算完成的。

2.1.5 逻辑查询优化包括的技术

1)子查询优化;

2)视图重写;

3)等价谓词重写;

4)条件化简;

5)外连接消除;

6)嵌套连接消除;

7)连接消除;

8)语义优化;

9)非SPJ的优化;

3. 什么是物理查询优化

总得来说:代价模型+索引/索引的利用+单表扫描算法+两表连接算法+多表连接算法=物理查询优化

4. MYSQL的执行计划

4.1 语法格式:

EXPLAIN [explain_type] explainable_stmt

可选项包括:

EXTENDED

PARTITIONS

FORMAT

= formatname

formatname:

TRADITIONAL

JSON

说明: 

    1.EXPLAIN命令,显示SQL语句的查询执行计划。

    2.EXPLAIN EXTENDED命令,显示SQL语句的详细的查询执行计划;之后可以通过“SHOW WARNINGS”命令查看详细的信息。

    3.EXPLAIN PARTITIONS命令,显示SQL语句的带有分区表信息的查询执行计划。

    4.EXPLAIN命令的输出格式有两种。

        4.1 TRADITIONAL:传统类型;按行隔离,每行标识一个子操作。

        4.2 JSON:JSON格式。

    5.explainable_stmt,可被EXPLAIN执行的SQL语句,包括的类型有:SELECT、INSERT、UPDATE、DELETE。

执行五表连接的查询语句如下:

EXPLAIN

SELECT *

FROM (t1 LEFT JOIN t2 ON true), (t3 FULL JOIN t4 ON true), t5

WHERE id1=id2 AND

id2=id3 AND

id3=id4 AND

id4=id5;

说明执行顺序:

1)从第1行到第9行,表示了完整的查询执行计划。

2)第1行到第3行,表明查询计划的结构;id表示对象被操作的顺序;id值大,先被执行;如果相同,执行顺序从上到下;

 3)从第4行起,每一行为一个节点,表示本节点被操作对象的可用信息,如索引等;

4)表的连接次序为:t4 t5 t3 t1 t2。这和初始给定的连接次序不同,经过优化,外连接被消除;

5)t4表的元组数最少,按照MySQL多表连接算法,表经过排序后,顺序为 t4 t5 t2 t3 t1;

6)因为t5、t3、t1上有索引可以利用,所以t4上的一条元组确定后,则可以利用索引之间定位t5、t3、t1表上的元组,所以第5、6、7行的key列有索引可用;ref列表明这三个表都是引用了t4表的id4列;

7)t2表的数据相对较多,且又没有索引,最后被连接,连接使用了Extra列表明的块嵌套循环连接算法,并且使用了连接缓存。

这里使用到了MYSQL块嵌套循环算法:

结点解析:

1)id:每个被独立执行的操作的标识,表示对象被操作的顺序;id值大,先被执行;如果相同,执行顺序从上到下;

2)select_type:查询中每个select子句的类型(读者可以自行百度查询);

3)table:名字,被操作的对象名称,通常是表名,但有其他格式。

4)partitions:匹配的分区信息(对于非分区表值为NULL)。

5)type:连接操作的类型(读者可以自行百度查询);

6)possible_keys:备选的索引(列出可能被使用到的索引);

7)key:经优化器选定的索引;常用“ANALYZE TABLE”命令可以使优化器正确地选择索引;

8)key_len:被优化器选定的索引键的长度,单位是字节;

9)ref:表示本行被操作的对象的参照对象(被参照的对象可能是一个常量用“const”表示,也可能是其他表的key指向的对象);

10)rows:查询执行所扫描的元组个数(对于InnoDB,此值是个估计值);

11)filtered:按照条件表上数据被过滤的元组个数的百分比,“rows×filtered/100”可以求出过滤后的元组数即实际的元组数。

以上是关于数据库查询优化技术的主要内容,如果未能解决你的问题,请参考以下文章

Mysql查询优化从入门到跑路数据库查询优化技术总揽

数据库查询处理及优化

如何做SqlServer 数据查询优化!

为啥目前的数据库查询优化技术不支持计算列的优化?

第九章 关系查询处理和查询优化——关系数据库系统的查询处理

数据库 chapter 9 关系查询处理和查询优化