关于ACS和参数化参数问题

【 使用环境 】生产环境 or 测试环境
【 OB or 其他组件 】OB
【 使用版本 】v4.2.5
【问题描述】

  1. 开启ACS(Adaptive Cursor Sharing)可能存在哪些隐患?有哪些业务场景下必须关闭ACS?
  2. cursor_sharing 与 enable_ps_parameterize 均控制SQL参数化行为,二者配置保持一致是否为最优选择?是否存在特殊场景,需要对两个参数设置不同的行为策略?

https://www.oceanbase.com/knowledge-base/oceanbase-database-20000001036
https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005685164
https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000002200913

3 个赞

66666

2 个赞

这个还是一个新的技术

2 个赞

6666

2 个赞

@论坛小助手

2 个赞

签到…

2 个赞

这个问题不清楚,大家集思广益,共同学习。

2 个赞

66

2 个赞

这怎么又涉及企业版了,官网相关文档介绍的时候根本没提企业版。

2 个赞

二、开启 ACS 可能带来的隐患

ACS 不是独立租户开关,而是参数化 + Plan Cache 上的自适应能力,风险主要来自多计划共存与反馈学习。

1. 计划缓存与内存压力

  • 同一参数化 SQL 可能缓存多个计划 + ACS_SEL_INFO 元数据。
  • Plan Cache 体积上升,淘汰更频繁,可能连带影响其他 SQL 命中率。

2. 性能抖动与“学习期”劣化

  • 首次或进入新选择率区间时可能硬解析生成新计划。
  • 反馈未稳定前,可能出现“这次快、下次慢”的抖动。
  • ADAPTIVE_FEEDBACK_TIMES 反映连续正/负反馈,说明存在演进过程。

3. 无法根治“大小账号”

官方 FAQ 对“大小账号”的描述与 ACS 场景高度重合:

200.sql-related-problems-faq.mdLines 371-377

“大小账号”问题是指在SQL语句解析和执行过程中,由于相同的SQL ID对应不同的执行计划,导致不同查询条件下的性能表现差异显著。例如,当某条SQL语句被参数化后,计划缓存中可能存在一个不适合所有情况的执行计划。这会造成以下影响:

当系统首次执行某条SQL(如select * from items where store = 'taobao';)时,执行计划(p1)可能是全表扫描,适用于选择率极低情况。

如果之后执行另一条参数化SQL(如select * from items where store = 'xiaomaibu';),且选择率很高,原本的计划p1可能就不再是最优方案,导致性能下降。

ACS 在“存在可接受的单一计划”时可能缓解;若小/大账号需要完全不同的路径(索引 vs 全表、不同 join 顺序),ACS 仍可能:

  • 学习慢、选错区间;
  • 区间内计划仍非最优;
  • 与 SPM 演进、计划淘汰策略交织,排查更难。

4. 统计信息与反馈失真

  • 估行/选择率偏差会导致 ACS 划错区间或选错计划。
  • 数据分布突变后,旧区间计划可能长期“半生效”。

5. 运维与诊断复杂度

  • 同一 SQL_ID 对应多个 PLAN_HASH,需结合 ACS_SEL_INFOQUERY_SQLPARAM_INFOS 分析。
  • Outline/SPM 固定计划时,可能与 ACS 多计划逻辑产生预期外交互(代码中曾有 is_spm_acs_closed_ 相关分支)。

6. 与 SPM 的叠加效应

V4.2.1+ 建议用 SPM 缓解大小账号;SPM 在线演进 + ACS 多计划,会同时改变“用哪个计划”,问题定位需同时看 baseline 与 Plan Cache。

三、哪些业务场景应“关闭 ACS 效果”

OceanBase 没有单独的 enable_acs 租户参数;实践中通过关闭参数化或禁止计划复用来规避 ACS:

手段 作用
SET cursor_sharing = 'EXACT'(全局/会话) 文本 SQL 不做 Fast Parser 参数化
/*+ CURSOR_SHARING_EXACT */ 单条 SQL 禁止参数化
/*+ USE_PLAN_CACHE(NONE) */ / ob_enable_plan_cache=0 不缓存计划,ACS 无从谈起
Outline 绑定固定计划 稳定执行路径,避免自适应切换

建议优先考虑关闭参数化/ACS 的场景:

  1. 典型大小账号:同一模板下过滤性差异极大(租户 ID、店铺、日期范围等),且无法用单一计划兼顾。
  2. 已做执行计划绑定:Outline、SPM FIXED baseline、SQL Plan Baseline 要求计划稳定可复现。
  3. 压测/对账/回放:需要相同 SQL 文本 → 相同 PLAN_HASH,排除自适应干扰。
  4. 计划抖动已观测:GV$OB_PLAN_CACHE_PLAN_STATIS_BIND_AWARE=1PLAN_HASH 频繁变化、RT 波动大。
  5. 统计信息不可靠:新表、直方图缺失、大批量加载后尚未收集统计信息。
  6. Plan Cache 紧张:内存告警、频繁淘汰,多计划加剧问题。

对大账号侧,官方更推荐 CURSOR_SHARING_EXACT Hint 单独保留计划,而不是全局关 ACS:

200.sql-related-problems-faq.mdLines 428-429

  • 加索引:通过构建索引来提升查询性能。

  • cursor_sharing_exact hint:对大账号添加这个hint,以便让查询得到独立的执行计划。

四、cursor_sharingenable_ps_parameterize 的关系

二者不是同一开关,作用路径不同:

维度 cursor_sharing enable_ps_parameterize
类型 系统变量(Global/Session) 租户配置项(V4.3.5 BP4+)
默认值 FORCE True
作用对象 文本 SQL(Fast Parser / 普通查询) PS(Prepared Statement) 解析阶段
关闭时行为 EXACTget_enable_exact_mode() 为真,跳过 Fast Parser 参数化 false → PS 不走参数化进 PS Cache

ob_basic_session_info.hLines 1459-1461

bool get_enable_exact_mode() const

{

return sys_vars_cache_.get_cursor_sharing_mode() == ObCursorSharingMode::EXACT_MODE;

ob_sql.cppLines 1414-1422

} else if (session.is_enable_ps_parameterize() && pc_ctx.ps_need_parameterized_) {

info_ctx.ps_need_parameterization_ = true;

} else {

info_ctx.ps_need_parameterization_ = false;

ob_plan_cache.cppLines 722-731

bool enable_exact_mode = pc_ctx.sql_ctx_.session_info_->get_enable_exact_mode();

} else if (enable_exact_mode) {

(void)fp_result.pc_key_.name_.assign_ptr(raw_sql.ptr(), raw_sql.length());

结论:二者不必强行保持一致,因为文本链路与 PS 链路本来就分开设计。

五、是否“配置一致”为最优?

不一定。 更合理的做法是按接入方式分别配置。

常见推荐组合

场景 cursor_sharing enable_ps_parameterize 说明
通用 OLTP(文本 + PS 混用) FORCE True 最大 Plan Cache 复用;ACS 对两类入口均可能生效
以 PS 为主、需与客户端文本严格一致 FORCE False 文本仍参数化;PS 保持 no_param_sql 与 checksum 一致(见 ob_sql.cpp 注释)
大小账号严重、以文本 SQL 为主 EXACT 或 Hint 视 PS 是否也有大小账号 文本侧独立计划;PS 可单独 True 若仅 PS 有该问题
新建租户(当前代码默认) 通常仍为 FORCE False(创建租户时写入) 说明 PS 参数化在部分场景下更易出问题

ob_tenant_ddl_service.cppLines 2282-2315

ObString config_name_enable_ps_parameterize(“enable_ps_parameterize”);

ObString config_value_enable_ps_parameterize(“false”);

} else if (OB_FAIL(tenant_init_config.add_config(config_name_enable_ps_parameterize, config_value_enable_ps_parameterize))) {

需要刻意不一致的特殊场景

  1. 文本 SQL 要共享计划,PS 要保持字面量 SQL
  • cursor_sharing=FORCE + enable_ps_parameterize=false
  • 典型:JDBC/OCI Prepare 后 Execute 需与客户端原始 SQL 一致。
  1. 仅文本 SQL 存在大小账号,PS 绑定值分布稳定
  • 大账号文本 SQL 用 CURSOR_SHARING_EXACT;PS 保持 enable_ps_parameterize=true 以复用计划。
  1. 仅 PS 存在参数化问题(如部分函数/JSON 路径不能参数化)
  • enable_ps_parameterize=falsecursor_sharing 仍可 FORCE
  • 部分语句会因 ps_need_parameterized_=false 自动跳过(如 concatjson_* 等)。
  1. 压测基线 + 生产 PS
  • 压测会话 cursor_sharing=EXACT;生产租户 PS 开启参数化。
2 个赞

这个答复比较权威了哦