当 last_analyzed 和 stale_stats 为 null 时是什么意思

What does it mean when last_analyzed and stale_stats is null

我们目前正在 运行ning Oracle 11g,我正在研究是否需要 运行 大量导入后的统计数据。我们将 statistics_level 设置为 'TYPICAL'。基于此,我认为我们不需要更新统计信息:

Starting with Oracle Database 11g, the MONITORING and NOMONITORING keywords have been deprecated and statistics are collected automatically.

https://docs.oracle.com/cd/B28359_01/server.111/b28310/tables005.htm

但是,在创建了我的数据库并 运行 进行了适度的导入之后(在少数 table 中创建了数以千计到数百万条记录并创建了许多索引)所有使用下面的查询,table 受导入影响的 last_analyzed 和 stale_stats 显示为空。

select 
    table_name, 
    stale_stats, 
    last_analyzed
from 
    dba_tab_statistics
 where 
    owner = 'MY_SCHEMA'
order by 
    last_analyzed desc, table_name asc
;

我是否应该期望某些查询在此状态下性能不佳?

我是否应该期望最终填充 运行 和 last_analyzed 以及 stale_stats 的统计信息(文档建议默认情况下这些值大约每三个小时更新一次)?

根据我的经验,对于中等规模的数据库(table 有数百万条记录和少于 10 条的数百万条记录)没有必要乱搞统计数据,而且通常会导致比它更多的问题解决。一般是这样吗?

* * * 关于我们决议的注释 * * *

我们正在使用这个:

analyze table my_table compute statistics

我们切换到这个:

dbms_stats.gather_table_stats('MY_SCHEMA', 'MY_TABLE');

分析 table 语句在一个环境中花费了大约 1:30 分钟,在第二个环境中花费了大约 15:00 - 20:00 分钟。

在我们能够检查的两个实例中,gather_table_stats 语句花费了大约 0:30 到 1:00 分钟。

我们的下一步计划是将我们的分析 table 语句切换为 gather_table_stats 调用。

STATISTICS_LEVEL 和收集 table/index 统计数据是完全不同的事情。 STATISTICS_LEVEL 影响是否在命令执行期间收集行源统计信息。这样您就可以比较显示光标中每个步骤的优化器估计值和实际值。

因此 table/index 统计信息用于执行计划优化,STATISTICS_LEVEL 用于在执行计划执行时收集执行统计信息,主要用于诊断目的。

last_analyzed 为 null 时,表示尚未收集 table 统计信息。

stale_stats 表示统计数据是新鲜的还是陈旧的,或者统计数据是否会在下次自动收集。默认设置为 10%。如果您收集 table 统计信息,然后 insert/update/delete 不到 10% 的行,则认为统计信息是最新的。当您达到 10% 的已修改行时,它们就会变得陈旧。

Oracle 默认情况下会在维护期间自动收集 table/index 统计信息 window,这是在创建数据库时自动配置的。如果有特定要求,通常由 DBA 重新配置。

关于 STATISTICS_LEVEL,默认值 TYPICAL 看起来像这样:

HUSQVIK@hq_pdb_tcp> select * from dual;

D
-
X
HUSQVIK@hq_pdb_tcp> SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------
SQL_ID  a5ks9fhw2v9s1, child number 0
-------------------------------------
select * from dual

Plan hash value: 272002086

-------------------------------------------
| Id  | Operation         | Name | E-Rows |
-------------------------------------------
|   0 | SELECT STATEMENT  |      |        |
|   1 |  TABLE ACCESS FULL| DUAL |      1 |
-------------------------------------------

Note
-----
   - Warning: basic plan statistics not available. These are only collected when:
       * hint 'gather_plan_statistics' is used for the statement or
       * parameter 'statistics_level' is set to 'ALL', at session or system level

我们没有看到超过估计行数的任何内容。如果你设置 ALTER SESSION SET statistics_level = ALL 那么

HUSQVIK@hq_pdb_tcp> ALTER SESSION SET statistics_level = ALL;
HUSQVIK@hq_pdb_tcp> select * from dual;

D
-
X
HUSQVIK@hq_pdb_tcp> SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------
SQL_ID  a5ks9fhw2v9s1, child number 1
-------------------------------------
select * from dual

Plan hash value: 272002086

------------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |      1 |00:00:00.01 |       3 |
|   1 |  TABLE ACCESS FULL| DUAL |      1 |      1 |      1 |00:00:00.01 |       3 |
------------------------------------------------------------------------------------

现在我们还可以看到实际的行数和执行每个步骤所花费的时间以及一致读取的数量(缓冲区列)。

对于更复杂的查询,您将获得比这更多的信息。您应该在 https://docs.oracle.com/database/121/ARPLS/d_xplan.htm

查看文档

另请注意,统计采样并非对每一行进行,而是默认情况下每 128 行进行一次(可以使用未记录的 _rowsource_statistics_sampfreq 参数进行更改)

(Husqvik 彻底解释了列和参数的含义,此答案仅解决如何收集统计信息。)

在对 table 进行任何重大* 更改后,应手动收集统计信息。自 11g 以来,Oracle 有一个很棒的默认自动统计信息收集过程。但即使有了这个新系统,仍然至少有两个充分的理由需要手动收集统计数据。默认统计信息收集自动任务通常用于缓慢变化的 OLTP tables,而不是快速变化的数据仓库 tables。

  1. 重大数据更改很容易导致严重的性能问题。如果table加载后立即使用,那么他们立即需要良好的统计数据。

    ETL 过程中的一个常见问题是当 tables 从 1 行变成一百万行时。优化器认为大型 table 中仍然只有一行,并使用大量嵌套循环连接而不是散列连接。这些算法在不同的环境中运行良好;没有良好的统计数据,Oracle 不知道正确的上下文。

    重要的是要注意 NULL LAST_ANALYZED 并不是最坏的情况。当根本没有统计数据时,Oracle 将使用动态抽样来生成快速统计估计。最坏的情况是昨晚统计作业运行时table为空; Oracle 认为它有很好的统计数据,但实际上并没有。

  2. 统计自动任务可能跟不上大的变化。统计自动任务是低优先级、单线程的过程。如果留给自动处理的大 table 太多,在维护期间可能无法处理它们 window.


坏消息是开发人员不能忽视优化器统计信息。 DBA 不能稍后再处理它。阅读手册中的某些章节可能会有所帮助,例如 Managing Optimizer Statistics.

好消息是 Oracle 11g 终于有了不错的默认设置。您通常不需要处理这些参数。在大多数情况下,有一个简单的规则可以遵循:如果 table 发生显着变化,运行 this:

dbms_stats.gather_table_stats('SCHEMA_NAME', 'TABLE_NAME');

*: "Significant" 是一个主观词。就相对大小而言,变化通常是显着的,而不是绝对的。如果 table 当前只有一行,则向 table 添加一百万行很重要,但如果 table 有十亿行,则不重要。