SQL语句的优化是一个比较耗时的过程,随着SQL语句的复杂度增高,优化的时间也会越来越长。为了避免反复执行优化过程,生成的执行计划会加入到计划缓存中,以便再次执行该SQL时使用。每一个租户在每一台server上都有一个独立的计划缓存,用以缓存在此server上处理过的SQL计划。
在应用系统中,同一条SQL每次执行可能会使用不同的参数,为了减少计划缓存的大小,系统会首先将用户SQL的参数做参数化处理,得到与具体参数无关的SQL字符串,并使用该字符串作为计划缓存的键值,具体参数化过程请参见快速参数化章节的介绍。计划缓存是一个典型的Key-Value结构,Key就是参数化后的SQL字符串,Value就是该条SQL所对应的执行计划。在OceanBase的计划缓存中,SQL的执行计划可以分为本地计划、远程计划和分布式计划三种类型。在计划缓存中,同一条SQL根据其需要访问的数据不同,可能同时有这三种执行计划。对于某一条SQL的某一种执行计划,默认情况下OceanBase只会保留一个计划,该计划由第一次执行SQL时生成;但在某些情况下,同一条SQL的参数值可能会影响到计划的选择,计划缓存可能会根据需要,为不同的参数值保留不同的执行计划,从而保证每次执行时可以使用最合适的计划。
计划缓存的淘汰
计划缓存的淘汰是指将执行计划从计划缓存中删除,减少计划缓存对内存的使用,OceanBase 支持自动淘汰和手动淘汰两种方式。
自动淘汰
自动淘汰是指当计划缓存占用的内存达到了需要淘汰计划的内存上限(即淘汰计划的高水位线)时,对计划缓存中执行计划自动进行淘汰。
触发执行计划淘汰的条件每隔一段时间(具体时间间隔由配置项plan_cache_evict_interval设置)会自动检查是否需要进行执行计划淘汰,对于不同租户在不同server上的计划缓存,会分别进行检查。如果某个计划缓存占用的内存超过该租户设置的淘汰计划的高水位线,则触发计划缓存淘汰。
执行计划淘汰策略当触发计划缓存淘汰后,优先淘汰最久没被使用的执行计划,淘汰一部分执行计划后,当计划缓存使用的内存为该租户设置的淘汰计划的低水位线时,停止淘汰。
与计划缓存淘汰相关配置
plan_cache_evict_interval该配置项用于设置检查执行计划是否需要淘汰的间隔时间。
ob_plan_cache_percentage该系统变量用于设置计划缓存可使用内存占租户内存的百分比。计划缓存最多可使用内存(内存上限绝对值)为:租户内存上限 * ob_plan_cache_percentage/100;
ob_plan_cache_evict_high_percentage该系统变量用于设置触发计划缓存淘汰的内存大小在内存上限绝对值的百分比。触发计划缓存淘汰的内存大小(淘汰计划的高水位线) =
内存上限绝对值 * ob_plan_cache_evict_high_percentage/100
- ob_plan_cache_evict_low_percentage该系统变量设置停止淘汰计划时内存(淘汰计划的低水位线) =
内存上限绝对值 * ob_plan_cache_evict_low_percentage/100
- 举例如果租户内存大小为10G, ob_plan_cache_percentage=10, ob_plan_cache_evict_high_percentage=90, ob_plan_cache_evict_low_percentage=50,则计划缓存内存上限绝对值 = 10G * 10 / 100 = 1G;淘汰计划的高水位线 = 1G * 90 / 100 = 0.9G;淘汰计划的低水位线 = 1G * 50 / 100 = 0.5G;当该租户在某个server上计划缓存使用超过0.9G时,会触发淘汰,优先淘汰最久没执行的计划,当淘汰到使用内存只由0.5G时,则停止淘汰。 如果淘汰速度没有新计划生成速度快,计划缓存使用内存达到内存上限绝对值1G时,将不在往计划缓存中添加新计划,直到淘汰后使用的内存小于1G才会添加新计划到计划缓存中。
手动淘汰
手动淘汰是指强制将计划缓存中计划进行删除,现在支持指定不同租户对应的当前server或全部server中计划缓存全部删除,具体命令如下:
alter system flush plan cache [tenant_list] [global]
其中tenant\_list:tenant = 'tenant1, tenant2, tenant3….'
其中tenant_list和 global为可选字段:
- 如果tenant_list没有指定,则清空所有租户的计划缓存,否则只清空特定租户的。
- 如果global没有指定,则清空本机的计划缓存,否则清空该租户所在的所有server上的计划缓存。
计划缓存的刷新
计划缓存中执行计划可能因为各种原因失效,这时就需要将计划缓存中失效计划进行刷新,即将该执行计划删除然后重新优化生成后加入计划缓存。在如下场景下执行计划会失效需要对执行计划进行刷新:
SQL中涉及的表的SCHEMA进行变更时(比如添加索引,删除或增加列等),该SQL对应的在计划缓存中的执行计划将刷新;
SQL中涉及的表的统计信息重新收集时,该SQL对应的执行计划会刷新,由于OceanBase在合并时统一进行统计信息的收集,因此现在每次进行合并后,计划缓存中所有计划将刷新;
计划缓存的使用控制
是否使用计划缓存可以使用系统变量及hint进行控制。
系统变量控制ob_enable_plan_cache设置为ture时表示SQL请求可以使用计划缓存,设置为false时表示SQL请求不使用计划缓存。可进行session级和global级设置,默认使用该设置为true。
Hint控制/*+use_plan_cache(none)*/ , 该hint表示请求不使用计划缓存。/*+use_plan_cache(default)*/, 该hint表示使用计划缓存。
计划缓存暂不支持的场景
内存大小超过20M执行计划不加入计划缓存
如果该计划为分布式计划且涉及多个表,则不加入计划缓存
关于计划缓存的视图
执行计划相关视图包括
(g)v$plan_cache_stat : 记录每个计划缓存的状态,每个计划缓存在该视图中有一条记录。
(g)v$plan_cache_plan_stat :记录计划缓存中所有plan的具体信息及每个计划总的执行统计信息, 每个plan在该视图中一条记录。
(g)v$plan_cache_plan_explain : 记录某条SQL在计划缓存中的执行计划。