查询第一次执行较慢但在 Second/Third 次后执行得很快

Query Execute Slow First Time But Fast on Second/Third Time

我们在 Oracle 查询中看到一个非常奇怪的情况。下面的查询,

SELECT e.C1, MAX (e.Some) 
FROM MyTable e
WHERE e.Code = :Code
GROUP BY E.C1
ORDER BY MAX (e.Some)

请注意 table 包含大约 500 万条记录,代码是主键。

第一次尝试时,它 returns 60/70 秒后的值,但之后,它 returns 500 毫秒后的结果。

Oracle 中是否有任何参数嗅探或者我们可以在 Oracle 中使用 OPTION(RECOMPILE)?

它可能没有使用主键索引。尝试解释计划以检查。尝试使用规则库强制使用索引:

select /*+ RULE */ from ...

此外,请 DBA 进行 运行 table 分析以更新统计信息。

Oracle 查询在第二次或第三次执行时可能会加速的原因有多种:

  1. Buffer Cache - Oracle 会将经常使用的 table 和索引块放在内存中。最简单的检查方法是 运行 SQL*Plus 中的查询,启用 set autotrace on 后多次。如果 "physical reads" 的值在第一个 运行 之后消失,则缓存导致了差异。但是缓存也可以发生在存储或操作系统级别。
  2. 构建速度慢 parsing/execution - 在极少数情况下,Oracle 可能需要很长时间来构建初始执行计划。如果使用动态采样,则尤其如此,Oracle 将读取 table 的一部分以弥补不良的优化器统计信息。查找此问题的一种方法是在查询的同时查找 运行 的其他系统查询。另一个常见原因是错误的系统或固定对象统计信息,这意味着 Oracle 可能很难构建查询来检查权限等内容。
  3. 基数反馈 (11g)/统计反馈 (12c+) - 通过将预期基数与实际基数进行比较,优化器能够从错误中吸取教训。同样的SQL_ID在GV$SQL中有不同的PLAN_HASH_VALUE吗?如果是这样,执行计划会随着时间的推移而改变。
  4. 结果缓存 - Oracle 服务器和客户端可以存储查询结果。这种类型的缓存实际上比人们想象的要少得多,因为在实践中缓冲区缓存更有用——当你可以存储可以服务于多个查询的数据块时,为什么还要将单个特定结果存储在内存中?