Oracle 所有分区的cific时间间隔,而不是在加载每个分区的进程结束时。如果这是一个活动表,并且24小时都有恒定的数据负载,这可能是一个挑战,但由于这些是大型DW表,我真的怀疑情况是否如此。因此,最好的办法是在加载所有分区结束时收集统计信息,这将确保为数据发生更改或统计信息丢失的分区收集统计信息,并根据分区级别的统计信息和概要信息更新全局统计信息
然而,要做到这一点,您需要为表(11gR1)启用增量特性Oracle 所有分区的cific时间间隔,而不是在加载每个分区的进程结束时。如果这是一个活动表,并且24小时都有恒定的数据负载,这可能是一个挑战,但由于这些是大型DW表,我真的怀疑情况是否如此。因此,最好的办法是在加载所有分区结束时收集统计信息,这将确保为数据发生更改或统计信息丢失的分区收集统计信息,并根据分区级别的统计信息和概要信息更新全局统计信息,oracle,oracle11g,etl,data-warehouse,table-statistics,Oracle,Oracle11g,Etl,Data Warehouse,Table Statistics,然而,要做到这一点,您需要为表(11gR1)启用增量特性 EXEC DBMS_STATS.SET_TABLE_PREFS(“”,'BIG_TABLE','INCREMENTAL','TRUE') 在每次加载结束时,使用gather\u table\u STATS命令收集表统计信息。您不需要指定分区名称。另外,不要指定粒度参数 EXEC DBMS_STATS.GATHER_TABLE_STATS(“”,'BIG_TABLE')我设法用这个函数达成了一个不错的折衷方案 PROCEDURE gathe
EXEC DBMS_STATS.SET_TABLE_PREFS(“”,'BIG_TABLE','INCREMENTAL','TRUE')代码>
在每次加载结束时,使用gather\u table\u STATS
命令收集表统计信息。您不需要指定分区名称。另外,不要指定粒度参数
EXEC DBMS_STATS.GATHER_TABLE_STATS(“”,'BIG_TABLE')代码>我设法用这个函数达成了一个不错的折衷方案
PROCEDURE gather_tb_partiz(
p_tblname IN VARCHAR2,
p_partname IN VARCHAR2)
IS
v_stale all_tab_statistics.stale_stats%TYPE;
BEGIN
BEGIN
SELECT stale_stats
INTO v_stale
FROM user_tab_statistics
WHERE table_name = p_tblname
AND object_type = 'TABLE';
EXCEPTION
WHEN NO_DATA_FOUND THEN
v_stale := 'YES';
END;
IF v_stale = 'YES' THEN
dbms_stats.gather_table_stats(ownname=>myschema,
tabname=> p_tblname,
partname=>p_partname,
degree=>dbms_stats.auto_degree,
granularity=>'APPROX_GLOBAL AND PARTITION') ;
ELSE
dbms_stats.gather_table_stats(ownname=>myschema,
tabname=>p_tblname,
partname=>p_partname,
degree=>dbms_stats.auto_degree,
granularity=>'PARTITION') ;
END IF;
END gather_tb_partiz;
在每个ETL结束时,如果添加/删除/修改的行数足够少,以至于无法将表标记为过时(默认情况下为10%,可以使用stale_PERCENT参数进行调整),则我只收集分区统计信息;否则,我收集全局和分区统计信息
这使小分区的ETL保持快速,因为不需要重新聚集全局分区,而大分区是安全的,因为任何后续查询都会有新的统计信息,并且可能会使用最佳计划
不管怎样,增量统计都是启用的,因此每当需要重新计算全局数据时,它的速度相当快,因为它会聚合分区级别的统计数据,并且不会执行完全扫描
我不确定,在启用增量的情况下,“近似全局和分区”和“全局和分区”是否在某些方面有所不同,因为增量和近似都做基本相同的事情:在不进行完全扫描的情况下聚合统计数据和直方图。我以某种方式尝试序列化分区加载。我在做一个没有指定分区的+APPEND(我错了),这导致整个表被锁定,所以实际上不能有多个线程同时在同一个表上加载数据。但由于我们有16个多小时的进程,序列化(使用10个并发线程)并不是一种可行的方法。我们的流程有非常严格的截止日期。关于日志记录,据我所见,所有表都已处于日志记录模式,我无法对其进行任何更改;结束代码>。表修改数据似乎有一些脏读在进行——多个会话相互看到未提交的插入,一个会话可以清除所有会话的数据。我不认为这是特定于增量统计的。它可能有助于在调用DBMS\u STATS
之前插入和删除一个虚拟行,以帮助强制收集。我想发布更多信息,但我现在没有足够的时间给出完整的答案。不幸的是,我没有DBA权限,甚至连表所有者都没有。顺便说一句,文档中说“因为GATHER_*u STATS过程在内部刷新监控信息,所以在收集统计数据之前不必运行此过程。”我正在尝试只收集分区级别的统计数据(有效),并偶尔刷新全局数据,以避免此问题,直到我找到一个最终的解决方案。你应该提供更多的细节。什么时候开始插入?在可疑盗窃统计数据插入开始之前或之后?他们中的哪一个先完成插入?你花了多少时间来做这件事?收集偷窃数据要花多少时间?可能第一个分区上的收集正在进行,而第二个会话正在提交?第一个分区上的收集将在第二个分区仍在插入时启动。是否为表启用了增量维护功能?比如execdbms\u STATS.SET\u TABLE\u PREFS(“”,'BIG\u TABLE','INCREMENTAL','TRUE')代码>我试过了,考虑到所花费的时间,它的行为似乎类似于“全局和分区”。但我会再检查一遍。不,我错了。未指定粒度默认为“自动”,这将覆盖partname的存在。他正在收集所有被触摸分区的统计数据,即使指定了partname,我也只是验证了它。如果统计数据正在运行并且分区被修改了,它不会收集新的统计数据,那么它看起来像一个错误。是的,我做了。我检查了增量统计的所有先决条件是否都满足。我采用了类似的解决方案。在每次ETL加载之后,我检查全局统计数据是否过时,如果过时,我收集分区和全局,否则只收集分区。这提供了很好的性能,因为当我加载小分区时,它改变的行数不超过总行数的10%,也不需要更新全局。我无法遵循您的解决方案。正如我在最初的文章中所说的,每个表的每个分区都是独立于其他分区的,我们具有高度的并行性。一旦分区A加载到表1中,数据就开始处理并向前移动到表1(具有相同的分区A)。同时,我们可以接收partitionB,它必须以相同的方式同时加载和处理。我不能等待TabL1被完全加载和分析,我会浪费太多的时间。嗯,我认为你应该考虑收集统计数据,如果它们过时。在每次加载之后收集每个分区上的统计数据对我来说似乎有点过分,除非您是在9i或其他版本中,或者试图补偿处理这些数据的代码,并且编写得很糟糕。
dbms_stats.gather_table_stats(ownname=>myschema,
tabname=>big_table,
estimate_percent=>dbms_stats.auto_sample_size,
granularity=>'AUTO',
CASCADE=>dbms_stats.auto_cascade,
degree=>dbms_stats.auto_degree)
PARTITION NAME | LAST ANALYZED | NUM ROWS | BLOCKS | SAMPLE SIZE
-----------------------------------------------------------------------
PART1 | 04-MAR-2015 15:40:42 | 805731 | 20314 | 805731
PART2 | 04-MAR-2015 15:41:48 | 0 | 16234 | (null)
dbms_stats.gather_table_stats(ownname=>myschema,
tabname=>big_table,
partname=>part,
degree=>dbms_stats.auto_degree);
BEGIN
DBMS_STATS.SET_TABLE_PREFS(myschema,'BIG_TABLE','INCREMENTAL','TRUE');
END;
PROCEDURE gather_tb_partiz(
p_tblname IN VARCHAR2,
p_partname IN VARCHAR2)
IS
v_stale all_tab_statistics.stale_stats%TYPE;
BEGIN
BEGIN
SELECT stale_stats
INTO v_stale
FROM user_tab_statistics
WHERE table_name = p_tblname
AND object_type = 'TABLE';
EXCEPTION
WHEN NO_DATA_FOUND THEN
v_stale := 'YES';
END;
IF v_stale = 'YES' THEN
dbms_stats.gather_table_stats(ownname=>myschema,
tabname=> p_tblname,
partname=>p_partname,
degree=>dbms_stats.auto_degree,
granularity=>'APPROX_GLOBAL AND PARTITION') ;
ELSE
dbms_stats.gather_table_stats(ownname=>myschema,
tabname=>p_tblname,
partname=>p_partname,
degree=>dbms_stats.auto_degree,
granularity=>'PARTITION') ;
END IF;
END gather_tb_partiz;