计划缓存与 Hint

共 20 题
📑 题目列表 20 题
#
★★★

1. Hint 机制,MySQL 的 USE INDEX、FORCE INDEX、SQL Server 的 OPTION(RECOMPILE)?

MySQL 的 USE INDEX、FORCE INDEX 与 SQL Server 的 OPTION(RECOMPILE) 分别如何使用?它们的作用与适用场景?

  • USE INDEX 是建议、FORCE INDEX 是强制,语法与忽略条件
  • OPTION(RECOMPILE) 每次执行重新编译,规避参数嗅探但增加编译开销
  • Hint 是例外通道而非常规手段

MySQL 的 USE INDEX 是"建议":告诉优化器优先考虑指定索引,但若优化器认为全表扫描或他索引更优仍可忽略;FORCE INDEX 是"强制":要求必须使用指定索引,仅当索引完全不适用(如条件无法匹配该索引)时才退化。两者写在表名后(SELECT * FROM t FORCE INDEX(ix_a) WHERE ...),适合统计失真、优化器选错索引、连接顺序失控时的临时止血;根治仍需刷新统计或调整代价参数。

SQL Server 的 OPTION(RECOMPILE) 让本语句每次执行都重新编译生成新计划,避免计划缓存中的旧计划被复用——常用于参数嗅探导致的首个参数决定后续计划、或数据分布剧烈变化、语句依赖临时表/局部变量的场景,代价是每次多一次编译开销(CPU 上升)且不参与计划缓存。本质:Hint 是"优化器的例外通道",应记录原因、配套回归测试,长期依赖 Hint 而非修统计是反模式。

本题考察两种 Hint 体系的定位差异:MySQL 是"索引层面的建议/强制",SQL Server 是"编译行为层面的强制"。回答时给出语法、适用场景与代价,并强调例外通道的定位。

SELECT * FROM orders FORCE INDEX (idx_user_id) WHERE user_id = 100;
SELECT * FROM orders WHERE user_id = 100 OPTION (RECOMPILE);
#
★★★

2. MySQL 的 prepared statement 与 SQL 缓存?

MySQL 中 prepared statement 与 SQL 缓存有什么关系?prepared statement 如何避免重复解析与优化?

  • PREPARE(解析+优化+生成计划)与 EXECUTE(绑定参数执行)两阶段
  • 8.0 中计划随 prepared statement 缓存在会话内
  • 防注入与连接池下缓存的注意事项

MySQL 的 prepared statement 分两步:PREPARE 阶段完成语法解析、权限校验、优化与计划生成(语句以参数占位符形式提交);EXECUTE 阶段绑定具体参数值直接执行,从而避免每条不同参数值的 SQL 重复解析与优化,同时参数与 SQL 文本分离天然防止 SQL 注入。8.0 中计划随 prepared statement 缓存在会话内,重复 EXECUTE 直接复用;简单查询协议下则没有此优化,每条 SQL 都要走完整解析与优化。

注意点:① MySQL 的 prepared statement 计划按首次参数值生成(无 PG 的 generic/custom 双计划机制),参数分布变化大时计划可能陈旧;② 8.0 已移除 query cache,prepared statement 缓存与之无关;③ 连接池下缓存随连接生命周期存活,连接重建后需重新 PREPARE(存在预热成本),DDL 后旧 statement 可能失效需捕获错误重试。

本题考察 prepared statement 的两阶段机制与缓存归属:解析优化只在 PREPARE 做一次、计划缓存在会话内、与已移除的 query cache 区分。

#
★★★

3. PostgreSQL 中无原生 Hint 的解决,pg_hint_plan 扩展?

PostgreSQL 没有原生 Hint,如何用 pg_hint_plan 扩展施加提示?其原理与局限?

  • /*+ ... */ 注释语法:扫描方式、join 方法、join 顺序、临时 GUC
  • 原理:planner hook 在规划阶段覆盖决策
  • 局限:需加载扩展、SQL 改写后静默失效、可能锁死次优计划

pg_hint_plan 是第三方扩展(NTT 出品),通过自定义注释 /*+ SeqScan(t) HashJoin(a b) Leading(a b) */ 中的提示词控制规划器:可指定访问路径(SeqScan/IndexScan)、连接方法(NestLoop/HashJoin/MergeJoin)、连接顺序(Leading),甚至临时设置 GUC(如 Set(random_page_cost 1.1))。实现原理是注册 planner hook,在规划阶段拦截并覆盖对应决策,因此无需改写 SQL 文本。

局限:① 需要 shared_preload_libraries 加载扩展且版本与 PG 严格绑定,云托管 PG(如 RDS)可能无法安装;② Hint 只对结构匹配的查询生效,SQL 改写(视图合并、子查询展开)后可能静默失效,难以察觉;③ 统计信息大幅变化后 Hint 可能把次优计划锁死,丧失自适应能力;④ 无法施加 SQL Server/Oracle 式的"每执行重编译"类提示。生产上建议把 Hint 作为临时手段,配合统计校准(扩展统计、target)根治。

本题考察 pg_hint_plan 的机制与边界:hook 原理、语法能力、安装与版本约束、静默失效与锁死风险。

#
★★★

4. PostgreSQL 的 prepared statement 与 generic plan,何时使用自定义计划?

PostgreSQL 的 prepared statement 何时生成 generic plan,何时生成 custom plan?plan_cache_mode 如何控制?

  • 前 5 次执行用 custom plan,之后按代价比较决定
  • generic 代价 ≤ custom 代价×1.1 时固定 generic plan
  • 数据倾斜下的失配与 plan_cache_mode 的强制选项

PG 对 PREPARE 的语句采用"先试探后固化"策略:前 5 次执行使用 custom plan(把当前参数值代入估算选择率并重新规划),同时计算 generic plan(参数视为未知、按均匀分布估算)的代价;从第 6 次起,若 generic plan 的估算代价不超过 custom plan 的 1.1 倍(即 custom 相对 generic 的改进不足 10%),则固定使用 generic plan,否则继续按参数生成 custom plan。规则本质是"参数差异带来的计划收益能否抵消每次重新规划的代价"。

风险:数据倾斜下同一语句不同参数值的最优计划差异巨大(如 status='NORMAL' 走索引、status='X' 走全表),generic plan 用平均值估算可能对部分参数产生差计划。控制手段:plan_cache_mode 可设为 force_custom_plan(每次按参数规划,规划开销上升)或 force_generic_plan(统一用通用计划),也可对倾斜值拆分独立 SQL 或改用字面量。

本题考察 PG 计划选择的双计划机制:5 次试探、1.1 倍代价阈值、倾斜失配与 plan_cache_mode 的三种模式。

#
★★★

5. 计划缓存的失效(Invalidation),表结构变更、统计信息更新?

计划缓存何时失效?表结构变更、统计信息更新等事件如何使缓存计划失效?

  • 依赖追踪驱动的失效:DDL、索引增删、统计更新、权限与 GUC 变更
  • SQL Server 自动统计更新阈值触发重编译,PG 的 generic plan 重新评估
  • 高频 DDL 与统计抖动放大重编译成本

计划缓存失效由数据库的依赖追踪机制驱动:被缓存计划引用的对象发生"计划相关变更"时,条目作废。常见触发器:① 表结构变更(ALTER TABLE 增删列/索引、表重建)——所有涉及该表的缓存计划失效;② 统计信息更新——SQL Server 在数据变化超过自动统计阈值(约 500 行+表行数的 20%)时使计划失效并重编译,PG 中 generic plan 在统计变化后被重新评估、普通查询每次执行重新规划;③ 影响语义的对象变更——权限变化、search_path 变化、影响计划的 GUC(如 cost 参数、optimizer 开关)变更;④ 显式失效——SQL Server 的 sp_recompile、MySQL 的 DDL 后会话级 prepared statement 失效。

失效机制保证"计划不陈旧",但高频 DDL 或统计抖动会放大重新编译开销并引入计划波动:生产上应控制统计刷新节奏(避免过小的自动阈值)、避免频繁 DDL,并对关键语句监控重编译次数。

本题考察计划缓存的生命周期管理:依赖追踪的失效原则、四类常见触发器、以及"失效与抖动"的工程权衡。

#
★★★

6. 计划缓存(Plan Cache)的实现,参数化查询的复用?

计划缓存如何实现参数化查询的复用?SQL Server、Oracle、MySQL 与 PostgreSQL 的实现差异?

  • 参数化是计划复用的前提,文本规范化决定命中率
  • SQL Server 自动/强制参数化、Oracle cursor_sharing、MySQL 8.0 会话级缓存、PG 依赖 PREPARE
  • 非参数化 SQL 导致的缓存膨胀与编译锁竞争

计划缓存复用的前提是查询被参数化:应用层 prepared statement(占位符)或数据库自动参数化,使不同参数值共享同一计划。实现差异:SQL Server 支持自动参数化与强制参数化(forced parameterization),plan cache 以规范化 SQL 文本为键存储计划并维护依赖与失效;Oracle 用 cursor_sharing=FORCE 把字面量替换为绑定变量;MySQL 8.0 仅为 prepared statement 提供会话级计划缓存(普通 SQL 文本不做跨会话缓存,且大小写/空格差异影响匹配);PG 普通 SQL 每次重新规划,复用靠 PREPARE 语句的 generic plan 与连接池配合。

参数化程度直接决定缓存命中率:非参数化 SQL 会生成大量"一次使用"的缓存条目(SQL Server 的 single-use plans),挤占内存、增加编译开销与编译锁竞争;生产上建议统一 SQL 书写规范或启用强制参数化,同时为数据倾斜语句保留字面量分支。

本题考察四库计划缓存的实现差异:参数化机制、缓存键与作用域。回答时逐库对比并给出命中率治理建议。

#
★★★

7. PostgreSQL 扩展查询协议下的 prepared statement,Parse/Bind/Execute 如何复用解析与规划结果,与简单查询协议的性能差异?

PG 扩展查询协议中 Parse/Bind/Execute 三阶段各做什么?如何复用解析与规划结果?与简单查询协议的性能差异?

  • Parse:解析+分析+规划生成可复用 statement;Bind:绑定参数生成 portal;Execute:执行
  • 同一 statement 可被多次 Bind/Execute 复用
  • 高频短查询下扩展协议可减少 30%~70% 规划开销

扩展查询协议把执行拆为三段:Parse 接收 SQL 文本,完成解析、分析与规划,生成可复用的 statement(含计划);Bind 把具体参数值绑定到 statement 并指定结果格式,生成 portal(执行实例);Execute 执行 portal 返回结果。核心复用点:同一 statement 可被任意多次 Bind/Execute 复用——解析与规划只做一次,参数绑定与执行重复多次,与简单查询协议(每条消息都要走完整解析→规划→执行)相比省去大量 CPU。

性能差异在每秒上万次的高频短查询场景显著:扩展协议通常可减少 30%~70% 的规划开销,且配合 generic plan 机制(前 5 次 custom 试探后按代价固定)进一步降低重复规划;代价是实现复杂度高(协议状态机、错误处理),由驱动层(libpq 的 PQexecParams、JDBC 的 PreparedStatement)封装。连接池场景建议持久化 PREPARE 语句并在会话间复用,避免每次连接重建后重新 Parse。

本题考察扩展协议的机制与收益:三阶段职责、statement 复用原理、与简单协议的规划开销差异。

#
★★★

8. 参数嗅探(Parameter Sniffing)问题,第一次执行参数决定后续所有执行的计划?

什么是参数嗅探(Parameter Sniffing)?为什么第一次执行参数可能决定后续所有执行的计划?如何解决?

  • 首次编译时嗅探参数值生成计划并缓存,后续参数值变化计划不变
  • 数据倾斜下计划失配的典型场景
  • 解决方案:RECOMPILE、OPTIMIZE FOR UNKNOWN、代表性参数、Query Store、拆分 SQL

参数嗅探指 SQL Server(及其他带参数化计划缓存的数据库)在第一次编译带参数的语句时,用实际传入的参数值代入估算选择率并生成计划,之后该计划被缓存复用——即使后续调用传入完全不同的参数值。问题出现在数据倾斜场景:首个参数对应"返回 1 行"生成索引扫描计划,后续参数对应"返回 90% 行",复用该计划导致灾难性性能;本质是"一个计划无法同时最优于所有参数值"。

解决方案:① OPTION(RECOMPILE) 每次执行重新嗅探(用 CPU 换计划适配);② OPTION(OPTIMIZE FOR UNKNOWN) 不嗅探具体值、按默认密度估算,生成对所有参数"都不是最优但都可接受"的稳健计划;③ OPTIMIZE FOR (@p = 代表值) 指定代表性参数;④ Query Store 强制计划;⑤ 将倾斜值拆分为独立 SQL 分支(两个计划各配各的参数)。实践上先确认倾斜真实存在(对比两个参数的估计行数),再选择方案。

本题考察参数嗅探的机制与治理:首参决定计划的原因、倾斜失配场景、五类解决手段的取舍。

#
★★

9. 参数嗅探的解决方案,OPTIMIZE FOR UNKNOWN、RECOMPILE?

参数嗅探有哪些常用解决方案?OPTIMIZE FOR UNKNOWN 与 RECOMPILE 各自的原理、适用场景与代价?

  • RECOMPILE:每执行重编译贴合当前参数,代价是编译开销
  • OPTIMIZE FOR UNKNOWN:按默认密度估算,稳健但非最优
  • 选择标准:参数分布、执行频率、倾斜程度

RECOMPILE 让语句每次执行重新编译:计划永远贴合当前参数值,彻底消除嗅探失配,代价是每次多付编译成本(CPU 上升、计划缓存失效),适合执行频率低或参数差异极大的语句。OPTIMIZE FOR UNKNOWN 告诉优化器"不要用参数的具体值做选择率估算",改用列的默认密度(1/基数)与均匀假设,生成一个对所有参数"都可用"的稳健计划——适合参数值分布极宽、任何单值代表都会误导的场景;也可用 OPTIMIZE FOR (@p = 典型值) 指定代表性参数。

选择标准:倾斜严重且执行频率高 → UNKNOWN 或拆分 SQL;低频/大查询 → RECOMPILE;中间方案是 Query Store 强制计划加回归检测。实践上先确认倾斜真实存在(对比两个参数的估计行数),避免盲目加提示掩盖问题。

本题考察两类反嗅探手段的对比:RECOMPILE 是"每次贴合"、UNKNOWN 是"面向平均",按频率与倾斜度选择。

#
★★

10. OPTIMIZE FOR UNKNOWN 的实现?

OPTIMIZE FOR UNKNOWN 在 SQL Server 中如何实现?其估算行为的本质是什么?

  • 实现:用列统计的平均密度(1/distinct)估算,跳过直方图定位
  • 本质:与 PG generic plan 一致的"面向平均、规避极端"
  • 局限:严重倾斜场景可能仍失配,需 OPTIMIZE FOR 代表值或拆分 SQL

SQL Server 对 OPTIMIZE FOR UNKNOWN 的实现是:跳过对实际参数值的嗅探,优化器以列的密度信息(density = 1/去重基数)估算等值条件的选择率,而不是在直方图中定位具体参数值取频度——因此生成计划的依据是"平均选择率",对任何参数值既不依赖直方图桶频次、也不受倾斜干扰。

其本质与 PostgreSQL 的 generic plan 一致:参数视为未知、按均匀分布估算,都是"面向平均、规避极端"。局限:若真实参数严重倾斜(99% 是热点值),平均密度估算反而高估热点查询的选择率,热点值查询可能拿到差计划——此时更适合 OPTIMIZE FOR(热点代表值) 或拆分 SQL;对等值条件较多、涉及多列的语句,密度估算的误差会叠加。

本题考察 UNKNOWN 的实现机制:密度估算取代直方图定位,与 PG generic plan 的等价性,以及倾斜场景的局限。

#
★★

11. SQL Server OPTION(RECOMPILE)?

SQL Server 的 OPTION(RECOMPILE) 提示的作用、适用场景与注意事项?

  • 每执行重新编译、不缓存复用
  • 适用:参数嗅探失配、局部变量/临时表依赖、数据分布剧变
  • 注意事项:编译开销与锁竞争,高频语句慎用

OPTION(RECOMPILE) 是查询级提示:强制 SQL Server 每次执行该语句时重新编译生成全新计划,不参与计划缓存复用。典型场景:① 参数嗅探导致计划与当前参数失配;② 语句依赖局部变量或临时表的当前统计(旧计划按初始统计生成);③ 表数据分布快速变化、统计滞后;④ 语句本身执行次数少且每次参数差异大。

注意事项:重新编译消耗 CPU 并产生编译锁竞争,高频语句滥用会放大开销、降低吞吐;通常只对"低频且计划敏感"的语句使用。与 OPTIMIZE FOR UNKNOWN 的关系:RECOMPILE 用真实参数值生成贴合计划,UNKNOWN 生成稳健计划但不贴合——按"要适配度还是要稳定性"选择;也可通过 sp_recompile 或 Query Store 策略做更大范围的管理。

本题考察 RECOMPILE 的完整画像:机制(不缓存)、场景(失配/局部变量/剧变)、代价(编译开销)与对比选择。

#
★★

12. prepared statement 的缓存生命周期与内存管理,会话级 PREPARE 在连接池复用下的残留与失效场景,缓存条目过多时如何淘汰与控制内存占用?

prepared statement 的缓存生命周期如何管理?连接池复用下有哪些残留与失效场景?缓存条目过多时如何淘汰?

  • 生命周期:会话级,会话结束或 DEALLOCATE 释放
  • 连接池下的 DDL 失效、权限变更失效与内存残留
  • 上限控制:max_prepared_stmt_count、session_cached_cursors 与监控

prepared statement 缓存默认绑定会话:会话结束或显式 DEALLOCATE 后释放。连接池场景的关键问题是连接存活时间极长:① 残留——DDL(表结构/索引变更)后旧 prepared statement 失效,应用复用会报错(如 MySQL 的 ER_UNKNOWN_STMT_HANDLER),需捕获异常并重新 PREPARE;② 权限变更后旧 statement 的权限检查可能失败;③ 长期不用的 statement 持续占用内存(SQL 文本、解析树与计划)。

控制手段:MySQL 8.0 用 max_prepared_stmt_count 限制全局 prepared statement 总数(默认 16382),超出报错,需清理未使用的 PREPARE;Oracle 用 session_cached_cursors 控制会话游标缓存条目并 LRU 淘汰;PG 的 prepared statement 在会话结束时自动释放、无全局缓存,风险集中在连接池连接的长期累积,应控制 PREPARE 数量或定期 DEALLOCATE。生产上建议监控缓存条目数与命中率,并结合连接池 maxLifetime 周期性回收连接。

本题考察 prepared statement 的生命周期治理:会话级归属、连接池下的失效与残留、各库的上限与淘汰机制。

#
★★

13. FORCE INDEX 的适用场景,MySQL 统计信息失真或连接顺序失控时强制索引的代价,PostgreSQL 无同类 Hint 时如何通过统计信息与规划参数实现?

FORCE INDEX 适用于哪些场景?强制索引有什么代价?PG 没有同类 Hint 时如何实现类似效果?

  • 适用:统计失真、直方图缺失、连接顺序失控导致选错索引
  • 代价:计划锁死、掩盖根因、索引变更后失效
  • PG 替代链路:刷新统计 → 扩展统计/直方图 → cost 参数 → pg_hint_plan

FORCE INDEX 的适用场景是"优化器系统性选错":统计陈旧或采样失真(基数被严重低估/高估)、连接顺序失控导致驱动表错误、直方图缺失使选择性误判。代价与风险:① 计划被锁死——统计修复或数据分布变化后仍强制旧索引,反而次优;② 掩盖真实问题——应修统计而非打补丁;③ 索引删除/改名后语句报错或退化;④ 新查询形态(如新增 OR 条件)无法受益。

PG 无 FORCE INDEX 原生语法,等效手段按优先级:先 ANALYZE 刷新统计并验证;用 CREATE STATISTICS 扩展统计修正相关性估算;调 default_statistics_target 或列级 STATISTICS 提高精度;调 cost 参数(如 SSD 下调 random_page_cost);仍不行再用 pg_hint_plan 的 IndexScan 提示或改写 SQL。原则:Hint 是最后手段,先修根因。

本题考察 FORCE INDEX 的适用边界与 PG 的替代链路:先定位"为何选错",再按"统计→参数→Hint"的优先级处理。

#
★★

14. Hint 与优化器的协同?

Hint 与优化器如何协同?Hint 被忽略(不生效)的原因有哪些?

  • Hint 是约束搜索空间而非最终指令,代价函数仍在受限空间内比较
  • 忽略原因:语法/对象名错误、视图合并与子查询展开后引用消失、条件不满足
  • 诊断:EXPLAIN Note、optimizer trace、pg_hint_plan 的 unused hint 日志

Hint 与优化器的关系是"约束与搜索":Hint 通过裁剪搜索空间(限定索引、连接方法、连接顺序)引导优化器,最终仍由代价函数在受限空间内选择,因此:① 建议型 Hint(USE INDEX)在强制索引代价过高时会被忽略;② FORCE INDEX 仅在索引不可用(不存在、条件不匹配)时放弃;③ 连接方法/顺序 Hint 与语义冲突时被忽略。

被忽略的常见原因:Hint 语法或拼写错误、Hint 内对象名与语句别名不一致、视图合并/子查询展开导致引用对象消失、索引不可见(invisible)或已禁用、optimizer_switch 关闭了对应特性。诊断手段:MySQL 用 EXPLAIN 的 Note 提示与 optimizer trace 查看 Hint 是否被采纳;pg_hint_plan 会输出"unused hint"日志。原则:Hint 应声明性、可解释、配套回归测试,避免静默失效。

本题考察 Hint 的协同机制与失效排查:约束-搜索模型、五类忽略原因、两类诊断工具。

#
★★

15. 参数化查询与字面量查询的取舍,为什么生产库建议强制参数化(force_parameterize/cursor_sharing),何时必须保留字面量(数据倾斜严重)?

参数化查询与字面量查询如何取舍?为什么生产库建议强制参数化?什么场景必须保留字面量?

  • 参数化收益:计划复用、缓存命中、编译开销下降、防注入
  • 代价:计划"平均化",倾斜数据下失配
  • 取舍:OLTP 强制参数化为主,倾斜值保留字面量分支

参数化(绑定变量)让不同参数值共享同一计划,收益:① 计划缓存命中率上升,编译开销与编译锁竞争下降;② SQL 文本统一,避免海量字面量变体击穿缓存(缓存膨胀、内存压力);③ 参数与 SQL 分离防注入。代价:计划"平均化"——优化器拿不到具体值,无法利用直方图精确定位,倾斜数据下某些参数值可能拿到差计划。

取舍原则:OLTP 高频语句建议强制参数化(SQL Server forced parameterization、Oracle cursor_sharing=FORCE、应用层绑定变量),把编译开销降下来;但数据倾斜严重、各参数最优计划差异极大的场景必须保留字面量或拆分 SQL,让优化器用具体值结合直方图精确估算。折中方案:参数化为主 + 倾斜值单独字面量分支 + 监控计划缓存命中率与编译占比。

本题考察参数化策略的工程权衡:收益(复用/防膨胀/防注入)与代价(平均化),以及倾斜场景的例外处理。

#
★★

16. 计划缓存的内存与监控,如何查看计划缓存命中率、大小与淘汰,SQL Server 的 plan cache 压力如何诊断?

如何监控计划缓存?SQL Server 中如何查看计划缓存命中率、大小与淘汰压力并诊断问题?

  • SQL Server:sys.dm_exec_cached_plans、sys.dm_exec_query_stats、perfmon Plan Cache 计数器
  • 诊断:命中率低、single-use plans 多、重编译率高、内存淘汰
  • 对策:参数化治理、optimize for ad hoc workloads、监控编译占比

SQL Server 计划缓存的监控入口:sys.dm_exec_cached_plans(缓存条目、内存占用、引用计数)、sys.dm_exec_query_stats(每条计划的总执行/编译/重编译次数、平均耗时),配合 perfmon 的 SQLServer:Plan Cache 计数器(Cache Hit Ratio、Cache Pages、Cache Object Counts)。诊断思路:① 命中率长期偏低——检查是否大量非参数化语句(Cache Object Counts 高、single-use plans 多);② 重编译次数高——统计更新阈值触发频繁或 DDL 频繁(sys.dm_exec_query_stats 的 plan_generation_num 反映重编译);③ 内存压力——缓存 Pages 接近目标上限且出现淘汰,可查 DMV 的 removed 统计与内存压力事件。

治理手段:压缩非参数化 SQL(强制参数化)、开启 optimize for ad hoc workloads(单次使用计划只缓存 24 字节 stub 而非完整计划)、清理无用计划(DBCC FREEPROCCACHE 仅应急)、监控编译占 CPU 比例。PG 侧对应:pg_stat_statements 看 planning time 占比与 calls、pg_prepared_statements 查会话预编译语句;MySQL 8.0 用 performance_schema.prepared_statements_instances。

本题考察计划缓存的观测与治理:DMV/perfmon 入口、三类压力症状(命中率/单次计划/重编译)与对应手段。

#
★★

17. Oracle SQL Plan Management(SPM)与 SQL Profile,如何固定稳定计划并在计划变化时灰度验证,与 PostgreSQL 的稳定性手段有何对应?

Oracle 的 SQL Plan Management(SPM)与 SQL Profile 如何固定稳定计划?计划变化时如何灰度验证?与 PG 的稳定性手段如何对应?

  • SPM:SQL plan baselines,accepted/non-accepted 两级,演进验证后提升
  • SQL Profile:把一组优化器调整固定到语句
  • 对应关系:SQL Server Query Store 强制计划、PG 用 pg_hint_plan + 统计校准

Oracle SPM 的机制:把"已接受(accepted)"的计划基线(SQL plan baseline)与语句绑定,执行时只从 accepted 基线中选择;新计划默认标记为 non-accepted 进入演进池,不直接使用;DBA 通过演进流程让数据库对比新旧计划的执行表现(如耗时与消耗),达标后提升为 accepted——实现"计划变化的灰度验证",防止统计更新或版本升级导致计划回退。SQL Profile 则是把一组优化器调整(提示、基数修正)作为 profile 固定到语句,强制优化器输出特定形态计划,适合"已知最优形态"的固定。

对应关系:PG 无 SPM,最接近的手段是 pg_hint_plan 固定计划 + auto_explain 审计计划变化 + 统计校准(扩展统计、target)从源头稳定估算;SQL Server 的 Query Store(强制计划 + 回归检测 + 一键回滚)功能上与 SPM 最接近;MySQL 8.0 无 SPM,用优化器开关、直方图与监控对比实现近似控制。

本题考察计划稳定性的跨库实现:SPM 的两级基线演进机制、SQL Profile 的固定语义、以及四库的对应关系。

#
★★

18. 统计信息对计划缓存的影响,统计更新后为何需要主动失效缓存(RECOMPILE/Query Store),生产变更时如何控制计划抖动?

统计更新后为什么需要主动失效计划缓存?生产环境变更时如何控制计划抖动?

  • 旧计划基于旧统计,统计更新后可能失配
  • SQL Server 自动统计更新阈值触发重编译,PG 的 generic plan 重新评估
  • 控制手段:分批变更、统计校准、计划监控与固定

计划缓存中的计划基于旧统计生成,统计更新后估算基数变化,旧计划可能已非最优甚至错误(如按旧行数选择的 join 顺序)。SQL Server 通过自动统计更新(数据变化超过阈值:约 500 行 + 表行数的 20%)触发计划失效与重编译,保证计划跟踪统计;但重编译有成本与抖动风险,DBA 可在关键统计更新后主动 RECOMPILE 或依靠 Query Store 观察新旧计划对比、强制回滚次优计划。PG 机制不同:普通查询每次重新规划(无长期计划缓存),prepared statement 的 generic plan 在统计变化后被重新评估,因此"统计更新导致计划变化"是常态,抖动表现为临界点附近的计划切换。

生产控制手段:① 变更分批小步(避免一次性大量写入触发统计突变);② 统计校准先行(扩展统计、合理 target、直方图)让估算贴近真实、减少突变;③ 监控计划分布(pg_stat_statements、Query Store 计划版本),出现回退立即人工介入;④ 对关键语句用 Hint/SPM/强制计划锁定。

本题考察统计与缓存计划的联动:失效机制(自动阈值/重新评估)与生产防抖动的四层手段。

#

19. Oracle 的 Hint 语法?

Oracle 的 Hint 语法形式是什么?常用 Hint(INDEX、LEADING、USE_HASH 等)如何使用?

  • /*+ ... */ 注释紧跟 SELECT 后,多 Hint 空格分隔
  • 常用:INDEX、FULL、LEADING、USE_NL/USE_HASH/USE_MERGE、PARALLEL
  • 对象名须与别名一致,可被静默忽略,RBO 已废弃

Oracle Hint 写在 /*+ ... / 注释中并紧跟 SQL 关键字之后(SELECT 后第一处),多个 Hint 以空格分隔,如 SELECT /+ LEADING(e d) USE_NL(d) INDEX(e emp_idx) */ ...。常用 Hint:INDEX(别名 索引名) 或 INDEX(别名) 指定索引路径、FULL(别名) 强制全表扫描、LEADING(表...) 指定连接顺序、USE_NL/USE_HASH/USE_MERGE 指定连接方法、PARALLEL(n) 指定并行度、以及优化器模式 Hint(ALL_ROWS/FIRST_ROWS)。

注意:① Hint 内对象名必须与语句中的别名一致,否则静默忽略;② Hint 是"请求"而非"命令",条件不满足(索引不可见、被视图合并)时被忽略,需用 EXPLAIN PLAN 验证是否生效;③ Oracle 10g 起默认 CBO,RBO 及 RULE Hint 已废弃(10g 起弃用,12c 起不再支持)。

本题考察 Oracle Hint 的语法规范:注释位置、常用 Hint 清单、别名匹配与静默忽略的注意点。

SELECT /*+ LEADING(e d) USE_NL(d) INDEX(e emp_idx) */ *
FROM employees e JOIN departments d ON e.dept_id = d.id;
#

20. 分布式数据库中的 Hint 与计划缓存,TiDB/StarRocks 等分布式执行中 Hint 的作用范围与缓存粒度与单机数据库有何差异?

分布式数据库(TiDB、StarRocks)中 Hint 与计划缓存与单机数据库有何差异?作用范围与缓存粒度?

  • Hint 更多是局部约束(单机算子),跨节点 shuffle 由分布式优化器决策
  • 计划缓存按语句 + schema 版本管理,region 变化不触发失效
  • 统计按 region/分片采样汇总、误差更大,计划抖动概率更高

分布式数据库的 Hint 与计划缓存与单机主要有三点差异:① 作用范围——单机 Hint 影响整棵计划树;分布式(如 TiDB)中 Hint 更多是"局部约束":索引/join 方法 Hint 作用于某台 TiKV 上的算子,而跨节点数据重分布(shuffle)、region 分布与并行度由分布式优化器统一决策,可通过会话变量(tidb_opt_* 系列)影响;StarRocks 的 Hint(如 USE_INDEX、SET_VAR、物化视图优先)作用于单机执行片段。② 计划缓存粒度——TiDB 支持 prepared statement 计划缓存(按 SQL 文本 + schema 版本失效,region 变化不触发失效),缓存粒度通常比单机更粗,需在"复用收益"与"数据分布变化导致的计划失配"间权衡。③ 统计信息——分布式统计按 region/分片采样再汇总,误差更大、更新更频繁,计划抖动概率更高,因此分布式产品更强调 Hint/会话级调优通道与计划回归监控。

本题考察分布式优化器的差异面:Hint 的局部性、缓存失效粒度(schema 版本)、统计采样的分布式误差。回答时以 TiDB/StarRocks 为例给出三点对比。