1.执行计划缓存
执行计划缓存
◼ 一次完整的语法解析、语义分析、查询改写、查询优化、代码生成的SQL编译流程称为一次“硬解析”,硬解析生
成执行计划的过程比较耗时(一般为毫秒级),这对于OLTP语句来说是很难接受的
◼ OceanBase通过计划缓存(Plan Cache)来避免SQL硬解析
计划缓存例子
mysql> select * from v$plan_cache_plan_stat limit 1 \G
*************************** 1. row ***************************
tenant_id: 1
svr_ip: 10.11.1.1
svr_port: 43225
plan_id: 391
sql_id: 555FFA5F489B7ACCBE66F9C830F03B09
type: 2 --remote计划
statement: SELECT data_version,row_count,data_size FROM __all_root_table
WHERE TENANT_ID = ? AND TABLE_ID=? AND PARTITION_ID=? ORDER BY data_version DESC --参数化SQL
query_sql:SELECT data_version,row_count,data_size FROM __all_root_table
WHERE TENANT_ID = 1 AND TABLE_ID=1 AND PARTITION_ID=1 ORDER BY data_version DESC
special_params:
sys_vars: 45,4194304,2,4,1,0,0,32,1,0,1,1,0,10485760,1 --第一次优化的查询
plan_hash: 17638921308295333636
first_load_time: 2017-05-19 14:52:24.579007
schema_version: 1495176592902432 --环境参数
merged_version: 2
last_active_time: 2017-05-19 16:07:12.971074
avg_exe_usec: 1304
slowest_exe_time: 1970-01-01 08:00:00.000000
slowest_exe_usec: 0
slow_count: 0
hit_count: 39
plan_size: 65536
2.执行计划缓存的淘汰-自动淘汰条件及策略
自动淘汰是指当计划缓存占用的内存达到了需要淘汰计划的内存上限(即淘汰计划的高水位线)时,
对计划缓存中的计划执行自动淘汰。
◼ 触发执行计划淘汰的条件
每隔一段时间(具体时间间隔由配置项 plan_cache_evict_interval 设置)系统会自动检查不同租户在不同服务
器上的计划缓存,并判断是否需要执行计划淘汰。如果某个计划缓存占用的内存超过该租户设置的淘汰计划的高
水位线,则会触发计划缓存淘汰
◼ 执行计划淘汰策略
当触发计划缓存淘汰后,优先淘汰最久没被使用的执行计划,淘汰一部分执行计划后,当计划缓存使用的内存为
该租户设置的淘汰计划的低水位线时,停止淘汰
内存高水位线开始淘汰不常用的执行计划,内存低水位先停止淘汰。
3.执行计划缓存的淘汰-自动淘汰相关配置
◼ 当计划缓存占用的内存达到了需要淘汰计划的内存上限(即淘汰计划的高水位线)时,对计划缓存中的执行计划自动进
行淘汰
◼ 优先淘汰最久没被使用的执行计划,影响淘汰策略的参数和变量如下:
⚫ plan_cache_evict_interval(parameter):检查执行计划是否需要淘汰的间隔时间
⚫ ob_plan_cache_percentage(variable):计划缓存可使用内存占租户内存的百分比 (最多可使用内存为:
租户内存上限 * ob_plan_cache_percentage/100)
⚫ ob_plan_cache_evict_high_percentage (variable) :计划缓存使用率(百分比)达到多少时,触发计划缓存
的淘汰
⚫ ob_plan_cache_evict_low_percentage (variable) :计划缓存使用率(百分比)达到多少时,停止计划缓存
的淘汰
4.执行计划缓存的淘汰-自动淘汰示例
◼ 如果租户内存大小为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才会添加新计划到计划缓存中
5.执行计划缓存的淘汰-手动淘汰
手动淘汰是指强制将计划缓存中计划进行删除。现在支持指定不同租户对应的当前服务器或全部服务器中
计划缓存全部删除,SQL 语句如下:
obclient>ALTER SYSTEM FLUSH PLAN CACHE [tenant_list] [global]
其中 tenant_list 和 global 为可选字段,使用说明如下:
◼ tenant_list 格式为 tenant = 'tenant_name, tenant_name….'。如果没有指定 tenant_list,
则清空所有租户的计划缓存。反之,则只清空特定租户的计划缓存
◼ 如果没有指定 global,则清空本机的计划缓存。反之,则清空该租户所在的所有服务器上的计划缓存
虽然可以手工清楚计划缓存,但是会对生产环境造成一定的影响。
6.执行计划缓存的刷新
计划缓存中执行计划可能因为各种原因而失效,这时需要将计划缓存中失效计划进行刷新,
即将该执行计划删除后重新优化生成计划再加入计划缓存。
如下场景会导致执行计划失效,需要对执行计划进行刷新:
◼ SQL 中涉及表的 Schema 变更时(比如添加索引、删除或增加列等),该 SQL 在计划缓存中所对应的执行计划将
被刷新
◼ SQL 中涉及重新收集表的统计信息时,该 SQL 在计划缓存中所对应的执行计划会被刷新。由于 OceanBase
数据库在数据合并时会统一进行统计信息的收集,因此在每次进行合并后,计划缓存中所有计划将被刷新
◼ SQL进行outline计划绑定变更时,该SQL对应的执行计划会被刷新,更新为按绑定的 outline 生成的执行计划
7.执行计划缓存的使用控制
计划缓存可以使用系统变量及 Hint 实现使用控制。
◼ 系统变量控制
⚫ 当 ob_enable_plan_cache 设置为 TURE 时,表示 SQL 请求可以使用计划缓存;设置为 FALSE 时,表示 SQL
请求不使用计划缓存。默认为 TURE。此系统变量可被设置为 Session 级别或者 Global 级别
◼ Hint 控制
⚫ 使用 Hint 语句 /*+USE_PLAN_CACHE(NONE)*/ 表示不使用计划缓存
⚫ 使用 Hint 语句 /*+USE_PLAN_CACHE(DEFAULT)*/ 表示使用计划缓存
8.执行计划缓存的相关视图及不支持的场景
◼ 计划缓存相关的视图:
⚫ (g)v$plan_cache_stat
记录每个计划缓存的状态,每个计划缓存在该视图中有一条记录。
⚫ (g)v$plan_cache_plan_stat
记录计划缓存中所有执行计划的具体信息及每个计划总的执行统计信息。
⚫ (g)v$plan_cache_plan_explain
记录某条 SQL 在计划缓存中的执行计划
◼ 计划缓存暂不支持的场景
⚫ 执行计划所占内存超过 20 MB 时,不会加入计划缓存
⚫ 如果该计划为分布式执行计划且涉及多个表,不会加入计划缓存
9.总结
1). 一个SQL的请求步骤:词法/语法解析生成语法树;缓存执行计划得已重用;语义解析将语法树生成内部数据结构;逻辑改写为与之等价的其他形式;优化器生成选择最佳执行计划;代码生成器转换可执行代码;执行器启动SQL的执行返回结果。
2). 通过 HINT 来指定访问路径或者通过改变连接顺序或连接算法等方法来达到加速查询。
3). 通过 Explain 命令查看优化器针对给定SQL生成的逻辑执行计划,通过v$plan_cache_plan_explain 虚表查看实时的执行计划。
4). 执行计划缓存可以通过设置淘汰条件及策略达到自动淘汰,也可以使用ALTER SYSTEM FLUSH PLAN CACHE来进行手动淘汰,使用 USE_PLAN_CACHE 的Hint可以指定是否使用执行计划缓存。