挑战
dbms_stats包使用两种主要的方式为分区的表和索引收集对象统计信息。
Ø 在对象、分区以及子分区级别上通过在每个级别上分别执行的查询来收集对象统计信息。
Ø 只在物理层面(可能是分区级别也可能是子分区级别)收集对象统计信息,并使用其结果来推算出其他级别的对象统计信息。
下面是这两种方式的两个关键区别。
Ø 总的来说,第一种收集对象统计信息的方式需要的时间和资源要高很多。实际上,在表/索引级别收集对象统计信息时,必须要访问所有的段。同样的事情也会发生在子分区对象的分区级别。例如,一张包含多年数据的按星期分区的表。如果一个分区发生了变化,那么必须访问所有分区才能更新表/索引级别统计信息。甚至在只有一个分区的数据被修改了的情况下,也必须访问所有分区。
Ø 第二种方式消耗的资源则要少很多,但是这种方式只能在物理级别生成准确的统计信息。这是因为它无法从底层的分区和子分区推算出不重复值的数量和直方图。顺便说一下,其他所有的统计信息都可以推算出来。
通过第一种方式收集的对象统计信息叫作全局统计信息。
通过第二种方式收集的统计信息叫作推算统计信息(有时也称作聚合统计信息)。
要辨别收集的是哪种类型,可以检查表8-2中列举的数据字典视图中global_stats列值是YES还是NO。只要可能,dbms_stats包就会收集全局统计信息。dbms_stats包只会在某些情况下收集推算统计信息,例如,收集的粒度被明确地限制在子分区级别并且在分区以及表/索引级别没有可用的对象统计信息时。
接下来的例子基于脚本global_stats.sql生成的输出,展示了这样的案例:对于一张按范围分区并按照hash进行子分区的表,其推算统计信息并不准确。注意,不仅表和分区级别的不重复值数量有误,global_stats列也被设置为NO。
Ø 在一张没有对象统计信息的表上执行子分区级别的收集(注意,没有涉及采样):
BEGIN
dbms_stats.delete_table_stats(ownname
=> user,
tabname =>
't');
dbms_stats.gather_table_stats(ownname
=> user,
tabname =>
't',
estimate_percent
=> 100,
granularity =>
'subpartition');
END;
/
Ø 在表级别的不重复值数量是错的,因为它们是通过推算统计信息收集的:
SELECT count(DISTINCT sp) FROM t;
SELECT num_distinct, global_stats
FROM user_tab_col_statistics
WHERE table_name = 'T'
AND column_name = 'SP';
Ø 在分区级别(这里指一个单独的分区)的不重复值数量也是错的,因为它们是通过推算统计信息收集的:
SELECT count(DISTINCT sp) FROM t PARTITION
(q1);
SELECT num_distinct, global_stats
FROM user_part_col_statistics
WHERE table_name = 'T'
AND partition_name = 'Q1'
AND column_name = 'SP';
Ø 在子分区级别(这里是对于单个分区来说的)的不重复值数量是正确的:
SELECT 'Q1_SP1' AS subpartition_name,
count(DISTINCT sp) FROM t SUBPARTITION (q1_sp1)
UNION ALL
SELECT 'Q1_SP2', count(DISTINCT sp) FROM t
SUBPARTITION (q1_sp2)
UNION ALL
SELECT 'Q1_SP3', count(DISTINCT sp) FROM t
SUBPARTITION (q1_sp3)
UNION ALL
SELECT 'Q1_SP4', count(DISTINCT sp) FROM t
SUBPARTITION (q1_sp4);
SELECT subpartition_name, num_distinct,
global_stats
FROM user_subpart_col_statistics
WHERE table_name = 'T'
AND column_name = 'SP'
AND subpartition_name LIKE 'Q1%'
ORDER BY subpartition_name;
警告 表/分区级别的对象统计信息,只有当底层的所有分区都有合适的对象统计信息时,才可以从底层的分区推算出来。这也适用于从子分区统计信息推算分区统计信息。此外,要知道dbms_stats包不会使用推算统计信息替代全局统计信息。两种情形都可以通过脚本global_stats.sql重现出来。
概括起来,全局统计信息要比推算统计信息更加精确,但是需要更多的时间和资源来进行收集。有时候可能推算统计信息就足够了。因此在实践中,对于大表来说,在准确度与达到目的所需的时间和资源之间找到均衡点很重要。基于这个原因,接下来的两节将描述可以用来管理足够大的表的对象统计信息的技术,进而防止重复收集完全的全局统计信息。