性能提升利器-执行计划缓存

thire
发布于 2022-9-20 11:35
浏览
0收藏

支持OLTP型业务的数据库系统,计划生成占执行消耗的比例很大,利用计划缓存来减少开销对系统性能至关重要。如何缓存计划?如何选择合适的缓存计划?

SQL是一种“描述型”语言。与“过程型”语言不同,用户在使用SQL时,只描述了“要做什么”,而不是“怎么做”。因此,数据库在接收到SQL查询时,必须为其生成一个“执行计划”,这个生成执行计划的过程叫做查询优化(Query Optimization)。查询优化是数据库中一个非常耗时的过程,随着SQL复杂度的增加,相应的计划空间也会呈指数级增长,所以当SQL本身执行耗时较短时,查询优化所带来的开销也变得不可忽略。一般来说,数据库在这种场景下会缓存之前生成的执行计划,以便在下次执行该SQL时直接使用,这种策略被称为“optimize once”,即“一次优化,多次使用”。在Oracle中,这种策略被称为Cursor Sharing。

计划缓存通常有两种模式,第一种是完全匹配模式,第二种是参数化匹配模式。SQL语句参数化是指将用户SQL的参数做参数化处理,得到与具体参数无关的SQL字符串。在完全匹配的模式下,SQL语句必须是一模一样的才能够匹配上相应的计划。在参数化匹配模式下,SQL语句只要参数化之后是相同的,就能够匹配上相应的计划。考虑如下的两个查询,在完全匹配的模式下,Q1和Q2是不能共享计划的,优化器会分别给它们生成计划,但是在参数化匹配模式下,Q1和Q2是可以共享计划的,因为它们参数化之后的SQL语句(见Q3)是一样的。

Q1: select * from t1, t2 where t1.a = t2.a and t1.b = 1 and t2.c = 2;

Q2: select * from t1, t2 where t1.a = t2.a and t1.b = 10 and t2.c = 20;

Q3: select * from t2, t2 where t1.a = t2.a and t1.b = ? and t2.c = ?;

在完全匹配模式下,用户缓存的计划是非常优的,但是它带来的问题是数据库需要缓存大量的执行计划(因为每个参数都对应一个执行计划)。在参数化匹配模式下,数据库需要缓存的执行计划会比完全匹配模式少很多,但是它带来的问题是计划的不优性,因为它意味着所有的参数都共享一个计划,这在有些场景下是非常不合理的。考虑如下的SCHEMA和SQL,如果b=1的选择率只有0.1%,那么Q1显然使用索引+回表的计划比较好,如果b=2的选择率有99%,那么Q2显然使用扫描主表的计划比较好,所以如果Q1和Q2共享一个计划,它必然不是最优的。

create table t1(a int primary key, b int, c int, index k1(b);

Q1: select * from t1 where b = 1;

Q2: select * from t1 where b = 2;

Oracle目前同时支持完全匹配模式和参数化匹配模式,用户可以设置相关的计划缓存模式。在OceanBase中,目前我们只支持参数化匹配模式,那么这个带来的问题就是所有的参数共享一个计划,从而可能会导致性能问题。如何解决不同参数使用不同的计划是参数化匹配模式必须要解决的问题,这个在学术界被称为Parametric Query Optimization[1,2,3,4,5]。在Oracle中,这个被称为Adaptive Cursor Sharing(ACS)。

Parametric Query Optimization的相关研究和实现都是基于如下的假设: 当一个查询中所有参数的选择率比较相近的时候,它们应该更加倾向于选择同一个计划。这个假设是合理的,因为如果参数的选择率比较相近,那么满足它们的条件行数也比较相近,这个时候它们理论上来说就会选择同一个计划。这里需要注意的是这个假设是基于参数的选择率,而不是基于参数,因为参数可能是离散的,而参数对应的选择率肯定是连续的。所以Parametric Query Optimization要解决的问题就是如何把选择率空间进行划分并为每个划分之后的子空间生成一个计划。下图展示了一个Parametric Query Optimization的例子,该例子把一个二维空间(带有两个参数)划分成了三个子空间,每个子空间使用了一个计划。理论上来说,如果可以缓存的计划是无限的,那么Parametric Query Optimization最终就会类似于完全匹配的模式,为每个参数选择一个计划,但是通常这是不合理的,所以Parametric Query Optimization通常需要控制计划的个数。

性能提升利器-执行计划缓存-鸿蒙开发者社区

OceanBase的Parametric Query Optimization过程主要由下图所示的两个参数(is_bind_seneitive和is_bind_aware)控制。变量is_bind_sensitive控制是否允许一个参数化SQL缓存多个计划。因为一些复杂的SQL通常会包含很多参数,那么这个SQL的参数化空间的维度就会很大,在这种场景下,Parametric Query Optimization 的复杂性就会很高,而且高维度的Parametric Query Optimization通常效果也会很差,所以OceanBase不会为这种SQL缓存多个计划。OceanBase在第一次为一个参数化SQL缓存计划的时候,会根据该SQL中表的个数,谓词的个数等因素来设置is_bind_sensitive的值。

is_bind_sensitive

是否允许一个参数化SQL缓存多个计划

is_bind_aware

是否真的为一个参数化SQL缓存多个计划 

如果is_bind_sensitive的值被设置为true,那么OceanBase就会开始监控该计划的每一次执行,然后根据执行反馈来决定是否需要为该SQL缓存多个计划。这种机制在OceanBase中被称为cardinality feedback,cardinality feedback主要监控扫描的行数,满足特定条件的行数等信息。变量is_bind_aware控制是否真的为该计划缓存多个计划,这个变量是由cardinality feedback来控制,如果一个参数化SQL每个执行时扫描的行数变化很大(既谓词选择率相差很大),那么该SQL很大程度上可能需要缓存多个计划, 否则不需要为该SQL缓存多个计划。

一旦变量is_bind_sensitive和is_bind_aware都被打开,那么数据库就会开始为该SQL缓存多个计划。OceanBase会为第一个缓存的计划计算出一个初始的选择率空间。比如一个SQL有两个谓词,并且该SQL第一次执行时两个谓词的选择率是(s1, s2), 那么第一个缓存的计划的选择率二维空间就是[(s1-δ,s1+δ),(s2-δ,s2+δ)],其中δ是一个事先预设的阀值。当下一个不同参数的SQL进来的时候,首先会计算谓词的选择率,如果该选择率在缓存计划的选择率空间内,那么我们就会直接使用该计划,否则优化器会重新生成一个计划。这个时候会出现如下两种情况:

  1. 计划是一个新的计划,那么我们会为该计划生成一个初始化的选择率空间。升级?
  2. 计划跟已有的计划相同,那么我们会把该计划的选择率空间和已有计划的选择率空间进行合并,生成一个新的选择率空间。

考虑如下的Schema和查询以及相关的谓词的选择率和计划:

schema:

create table t1(int primary key, 

int, c int, index k1(b))

选择率

计划

Q1:select * from t1 where b = 1;

sel(b=1) = 0.01

P1(选择索引)

Q2:select * from t1 where b = 2;

sel(b=2) = 0.25

P2(选择主表)

Q3:select * from t1 where b = 3;

sel(b=3) = 0.10

P1(选择索引)

Q4:select * from t1 where b = 5;

sel(b=5) = 0.50

P2(选择主表)

按照下图左侧显示的执行顺序,OceanBase的parametric query optimization的整个过程如右侧所示:

查询执行顺序

OceanBase相关表现

Q1

Q1的计划P1被缓存,同时因为该SQL的复杂度很低并且只有一个谓词,所以设置is_bind_sensitive = true;

Q4

使用P1执行Q4时,通过cardinality_feedback发现,在Q4和Q1的执行中扫描的行数差别很大,这个时候设置is_bind_ware = true, 同时初始化P1的选择率空间为(0.01-0,001, 0.01+0.001)(δ = 0.001)

Q2

因为Q2的选择率空间不在P2的选择率空间之内,所以重新为Q2生成了一个计划P2,P2和P1不同,所以初始化P2的选择率空间为(0.25-0.001, 0.25+0.001)

Q3

因为Q3不在P1和P2选择率空间之内,所以重新为Q3生成了一个计划P1,并且合并P1的选择率空间为(0.01-0.001, 0,10)

Q4

因为Q4不在P1和P2的选择率空间之内,所以重新为Q4生成了一个计划P2,并且合并P2的选择率空间为(0.25-0.001, 0.5)

[1] G. Graefe and K. Ward, “Dynamic Query Evaluation Plans,” Proc. ACM SIGMOD, 1989.

[2] G.M. Lohman, “Is Query Optimization a “Solved” Problem?” Proc. Workshop Database Query Optimization, Oregon Graduate Center Technical Report 89-005, 1989.

[3] V.G.V. Prasad, “Parametric Query Optimization: A Geometric Approach,” MSc thesis, IIT, Kampur, 1999.

[4] N. Reddy and J.R. Haritsa, “Analyzing Plan Diagrams of Database Query Optimizers,” Proc. 31st Int’l Conf. Very Large Data Bases (VLDB), 2005.

[5] A. Hulgeri and S. Sudarshan, “Parametric Query Optimization for Linear and Piecewise Linear Cost Functions,” Proc. 28th Int’l Conf. Very Large Data Bases (VLDB), 2002.

分类
标签
已于2022-9-20 11:35:53修改
收藏
回复
举报
回复
    相关推荐