我们有一个按月分区的大表范围。增量统计已开启。在预定的统计数据收集之后,基数估计变得很奇怪,比如
select count(*) from my_table where date >= trunc(sysdate) - 30 and date < trunc(sysdate)
给出 1.3M 行,但估计为 20K。只有在手动重新收集统计数据后,估计才会变得准确。代码示例:
-- Scheduled
dbms_stats.gather_table_stats
(
ownname=> 'ownname',
tabname=> 'tabname' ,
estimate_percent=> DBMS_STATS.AUTO_SAMPLE_SIZE,
cascade=> DBMS_STATS.AUTO_CASCADE,
degree=> 4,
no_invalidate=> DBMS_STATS.AUTO_INVALIDATE,
granularity=> 'AUTO',
method_opt=> 'FOR ALL COLUMNS SIZE AUTO'
);
-- Manual
DBMS_STATS.GATHER_TABLE_STATS
(
ownname => '"ownname"',
tabname => '"tabname"',
partname => '"partname"',
method_opt => 'FOR COLUMNS DATE SIZE 254',
estimate_percent => 1
);
其他分区表都没问题。
该表与其他表之间的区别是(据我们所知):
- 该表中存在错误插入。大多数日期在 2014 年和 2023 年之间,但有一些行包含 1970 年和 2024 年(我们无法更改它)。还有 2045 的空分区。我们尝试重新创建它,但没有得到相同的行为。
- 我们搞乱了直方图,删除了一些自动创建的直方图,并手动创建了一些基于函数的有用的直方图。但在 USER_TAB_COL_STATISTICS 和 USER_TAB_HISTOGRAMS 中,存在 DATE 列的直方图。
什么会导致这种行为?我们该如何解决它?
这是分区表中升序日期的常见问题。第一件事是验证增量统计数据是否有效。
您应该在每一列中看到“增量”。如果不这样做,那么您需要让增量统计数据正常工作。要使增量统计数据发挥作用,您必须设置以下选项:
然后,您必须使用这些设置收集统计数据一次,这最初将进行全局收集。首先删除表上的统计信息以从头开始可能是个好主意。然后,后续收集应该仅收集过时的分区并使用它来估计全局列最小/最大/不同值。
另外,您不希望日期列上有直方图,除非您有一个过度代表的神奇值(例如 12/31/9999),或者单行具有可追溯到 1970 年或 1900 年的虚假日期或某个愚蠢的日期到目前为止,简单的最小/最大平均值确实会很差。直方图用于倾斜,而不是像大多数日期列那样用于均匀分布的值。我想我记得读过直方图会覆盖增量统计数据,因此这可能是从始终升序的日期列中删除它们的另一个原因。在我们的大数据仓库中,我们在日期列上没有任何直方图,尤其是那些分区键的直方图。我们只依赖增量,它通常效果很好。
假设您的增量统计数据正在工作,接下来的事情是查看统计数据收集是否发生得太晚(错误的查询可能会在主要分区修改/加载之后很快执行,然后才有机会收集新数据的统计数据)。要检查这一点,请查看
LAST_ANALYZED
并与错误查询的开始时间和上次主要数据加载的时间进行交叉检查。您还可以仔细检查日期列的最大值是否大致正确。您必须根据其原始值对其进行解码。以下是一组可用于显示列的最小/最大值的函数:
现在查询统计数据:
当您的查询不好时(在收集统计信息之前)运行此命令,以查看最大值是否明显低于应有的值(以及可能晚几周或更长时间的日期)。这是统计数据未按时收集的另一个迹象。您可能需要在加载完成后调整统计信息收集窗口或将手动统计信息调用(不覆盖任何参数)添加到加载数据的代码中。
CARDINALITY
如果所有其他方法都失败了,并且您无法获得与您的应用程序模式相符的统计数据计时,那么您始终可以投入统计数据毛巾,并使用或提示来提示查询,告诉 Oracle 期望该表中有一百万行OPT_ESTIMATE
: