查询第一次执行慢,但第二次/第三次执行快

Posted

技术标签:

【中文标题】查询第一次执行慢,但第二次/第三次执行快【英文标题】:Query Execute Slow First Time But Fast on Second/Third Time 【发布时间】:2020-03-04 13:58:09 【问题描述】:

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

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

请注意,该表包含大约 500 万条记录,并且 Code 是主键。

第一次尝试时,它会在 60/70 秒内返回值,但之后,它会在 500 毫秒内返回结果。

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

【问题讨论】:

结果缓存已关闭? docs.oracle.com/database/121/TGDBA/… Google:Oracle 中的 RESULT_CACHE。 使用相同的 :Code 值?尝试查看统计数据,看看它在做什么。我怀疑第一次执行是从磁盘读取索引和表的块,所以它很慢(尽管 70 秒对于 5M 行来说太慢了,除非你有一个非常慢的磁盘子系统),下次它们在内存,所以没有 I/O。或者可能是 result_cache,正如其他人所建议的那样。 Oracle 中存在参数嗅探,称为自适应游标共享 (ACS)。 【参考方案1】:

Oracle 查询在第二次或第三次执行时可能会加快有几个原因:

    缓冲区缓存 - Oracle 会将经常使用的表和索引块放入内存中。检查这一点的最简单方法是在启用set autotrace on 后多次在SQL*Plus 中运行查询。如果“物理读取”的值在第一次运行后消失,那么缓存会导致差异。但缓存也可以发生在存储或操作系统级别。 解析/执行构建缓慢 - 在极少数情况下,Oracle 可能需要很长时间才能构建初始执行计划。如果使用动态采样,则尤其如此,Oracle 将读取表的一部分以弥补不良的优化器统计信息。查找此问题的一种方法是查找与您的查询同时运行的其他系统查询。造成这种情况的另一个常见原因是系统或固定对象统计信息不正确,这意味着 Oracle 可能很难构建查询来检查权限等内容。 基数反馈 (11g)/统计反馈 (12c+) - 通过比较预期基数和实际基数,优化器能够从错误中学习。相同的 SQL_ID 在 GV$SQL 中是否有不同的 PLAN_HASH_VALUE?如果是这样,则执行计划会随着时间而改变。 结果缓存 - Oracle 服务器和客户端可以存储查询的结果。这种类型的缓存实际上比人们想象的要少得多,因为实际上缓冲区缓存更有用 - 当您可以存储可以服务多个查询的数据块时,为什么要将单个特定结果存储在内存中?

【讨论】:

谢谢。我们也将数据复制到 SQL Server。相同数量的数据和相同的查询在第一次尝试时会在 1 秒内返回数据,不知道为什么 Oracle 在第一次尝试时总是很慢。 @user960567 数据是否也复制到了 Oracle?这些问题的一个常见原因是糟糕的优化器统计信息,这可能在加载表时发生。如果在有 0 行时收集表统计信息,然后将 500 万行加载到表中,则优化器将很难使用该信息构建良好的执行计划。即使您配置了默认统计任务,当数据发生显着变化时手动收集统计数据也很重要。 (但这是一个猜测 - 如果您添加更多信息,我可以更好地猜测根本原因。) Oracle 是该表的主源。同一个表被复制到 SQL Server。每天大约有数千行插入/更新。在用于缓解不良计划的 SQL Server 中,我们使用OPTION(RECOMPILE)。不幸的是,我在 Oracle 中没有看到类似的东西。无论如何,谢谢,乔恩。【参考方案2】:

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

select /*+ RULE */ from ...

另外,请 DBA 运行表分析以更新统计信息。

【讨论】:

以上是关于查询第一次执行慢,但第二次/第三次执行快的主要内容,如果未能解决你的问题,请参考以下文章

为什么Sql Server的查询有时候第一次执行很慢,第二次,第三次执行就变快了

mysql做查询时,第一次很慢,第二三次就会很快?

在QT中用 QSqlQuery query;查询, 第一次 query.exec();结果是对的,可是第二次执行的时候读的数据是错的

每次 TortoiseSVN(通过 *** 连接时)第一次失败,但第二次工作

cl 生成的可执行文件第一次运行非常慢

DELETE QUERY 第一次运行缓慢,但第二次(对于相同条件)运行快速 - 如何在第一次运行时使查询快速运行?