临时表在收集统计的时候会出现的问题
添加一个临时表:
SQL> create global temporary table gtt(x int) on commit preserve rows; 表已创建。 SQL> insert into gtt select rownum from all_objects where rownum <= 1000; 已创建1000行。 SQL> set autotrace on exp SQL> select count(*) from gtt; COUNT(*) ---------- 1000 执行计划 ---------------------------------------------------------- Plan hash value: 3344941513 ------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | TABLE ACCESS FULL| GTT | 1000 | 2 (0)| 00:00:01 | ------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement SQL> |
另外启动一个Session。
SQL> conn test/test 已连接。 SQL> select * from gtt; 未选定行 SQL> set autotrace on exp SQL> select * from gtt; 未选定行 执行计划 ---------------------------------------------------------- Plan hash value: 917624683 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 13 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS FULL| GTT | 1 | 13 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement SQL> |
这是正确的,但是如果我们使用dbms_stats.gather_table_stats这个收集一下临时表的统计信息时候,就会出现问题了。
#Session 1
SQL> exec dbms_stats.gather_table_stats(user,'GTT'); PL/SQL 过程已成功完成。 SQL> select count(*) from gtt; COUNT(*) ---------- 1000 执行计划 ---------------------------------------------------------- Plan hash value: 3344941513 ------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | TABLE ACCESS FULL| GTT | 1000 | 2 (0)| 00:00:01 | ------------------------------------------------------------------- |
这时可以看到这里使用的不是动态收集的选项,而是我们收集的统计信息,在这个会话中是正确的。
#Session 2
SQL> select * from gtt; 未选定行 执行计划 ---------------------------------------------------------- Plan hash value: 917624683 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1000 | 3000 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS FULL| GTT | 1000 | 3000 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------- |
这就出现问题,明明在这个会话中没有数据的,而执行计划上却显示有1000行的数据,这就造成了问题。
这个问题产生的原因是因为:临时表有两种类型的,一是会话级的,二是事务级的,而我们收集统计信息,但是由于临时表的特殊性,只是在一个会话上当时的情况下收集的,只能反应当时一个瞬间的数据的状态,由于临时表上的数据在会话之间,事务之间是变化的,这样就会产生这样的问题。
解决办法:
解决的方法有两种:
1、 在9i2之前由于没有动态采集信息的方案,建议根据临时表的典型特征来使用dbms_stats.set_table_stats来固定统计数据。
在 9i2 之后,可以使用动态采集,不需要人工对临时表进行统计数据的采集。来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/222350/viewspace-909443/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/222350/viewspace-909443/