在包内多次运行收集表统计信息会导致性能问题

Posted

技术标签:

【中文标题】在包内多次运行收集表统计信息会导致性能问题【英文标题】:Running gather table statistics multiple times inside a package causes Performance Issues 【发布时间】:2021-04-05 20:45:56 【问题描述】:

我们有一个总是遇到性能问题的大包。在一个月内,我们平均会收到 6-10 份针对此问题的票。有时程序会成功运行几分钟,有时它会运行几天,只是因为出现无法解释的错误而出错。

我开始对此进行深入研究,发现性能问题的可能原因有很多,例如大量未调整的 SQL 和糟糕的编码习惯等。

今天让我印象深刻的一件事是在代码中,它在执行一些大操作(例如巨大的 Select 语句和大量 DML 语句)之前在多个地方多次调用 Gather Table Statistics。

该计划每天、每周和每月运行一次,具体取决于组织的实践。

不幸的是,我无法复制性能问题以了解更多信息,但我猜测多次将 Gather Table 统计信息运行到多个表可能会导致程序出现重大性能问题。我找不到任何资源来支持这个想法。有人可以确认吗?

【问题讨论】:

您的数据更改速度有多快?你的数据是静态的,统计数据几乎不会改变吗?还是删除/截断表,然后创建新数据,这样每次执行的统计数据都会有显着差异? 正在收集的表就像临时表一样。这些表不会被删除,但它们确实会插入大量数据(从 0 到 777k),然后被删除。我见过一些运行,它在 1 小时内成功处理了 48k 条记录,然后在运行 4 天后又出现了相同数量的记录失败。 “正在收集的表就像临时表一样。”那你为什么不使用临时表呢?听起来您将使用当前方法生成大量撤消数据。 不幸的是,这段代码在这里的时间比我更长,而我基本上是一年前才到这里的。我认为他们没有使用真正的临时表的原因是因为可以选择不清除数据(出于调试目的或其他目的)。 @MT0 您始终可以创建带有n 分区的表(其中n 大于您的程序将同时运行的次数)并将该程序运行的所有数据存储在该分区,然后在运行完成后删除该分区。您可以使用循环序列存储当前分区号,并在每次运行开始时获取下一个序列号。 【参考方案1】:

是的,可以确认,已经看到花费 80% 的运行时收集统计信息的代码。鉴于您的限制,我会按以下顺序尝试:

    我会查看 DELETE 语句以检查它们是否可以替换为 TRUNCATE TABLE。 表格填满后收集统计数据,lock 他们的统计数据并注释掉任何其他gather_table_stats 调用。假设每天或每周的数据差异不会大到足以导致不同的查询计划。 如果这不起作用,我会尝试查看 DBA_TAB_MODIFICATIONS,以至少检查自上次收集统计信息以来表格是否已进行了足够的更改。

【讨论】:

以上是关于在包内多次运行收集表统计信息会导致性能问题的主要内容,如果未能解决你的问题,请参考以下文章

SQL查询性能统计消息多次返回

dbms_stats(性能调优)

通过手动创建统计信息优化sql查询性能案例

oracle中的统计信息问题

SQL调优技巧:统计信息(文末福利)

Oracle统计信息不准(谓词越界)造成的性能问题