truncate table, will the statistics be cleared?

I saw a friend in the WeChat group ask:

truncate table, will the statistics be cleared?


Some friends replied,

The data dictionary information is gone, and the statistical information is cleared, so there is no statistical information.

Do an experiment and track the truncate, it should be clear.

I did a 10g test and found that the last_analyzed of that table is still recorded.

Statistics are still there after truncate. It has nothing to do with your 10g or 11g. The key is whether you have collected statistics before. You haven't collected statistics before, and the last analyzed is empty.

There is a record before, last_analyzed is not empty, after truncate table, this becomes empty.


What the second friend said is quite right. Whether the statistics will be deleted or not, you can find out by doing an experiment.


Create a test table,

SQL> create table test (id number, name varchar2(1));
Table created.

SQL> begin
       for i in 1 .. 10000 loop
         insert into test values(i, dbms_random.string('a',1));
       end loop;
       commit;
     end;
     /
PL/SQL procedure successfully completed.

SQL> create index idx_test on test(id);
Index created.

SQL> select count(*) from test;
  COUNT(*)
----------
     10000


At this time, the statistical information of the retrieval table is empty, and the statistical information of the retrieval index is recorded.

SQL> select num_rows, to_char(last_analyzed,'yyyy-mm-dd hh24:mi:ss') last_analyzed from user_tables where table_name='TEST';
  NUM_ROWS LAST_ANALYZED
  --------------- -----------------------------------------


SQL> select num_rows, sample_size, to_char(last_analyzed,'yyyy-mm-dd hh24:mi:ss') last_analyzed from user_indexes where table_name='TEST';
  NUM_ROWS SAMPLE_SIZE LAST_ANALYZED
---------- ----------- -----------------------------
     10000          10000 2017-10-08 15:55:42


手工以cascade=false收集统计信息,

SQL> exec dbms_stats.gather_table_stats('BISAL','TEST',cascade=>false);
PL/SQL procedure successfully completed.


可以看出,表的统计信息已近更新了,

SQL> select num_rows, to_char(last_analyzed,'yyyy-mm-dd hh24:mi:ss') last_analyzed from user_tables where table_name='TEST';
  NUM_ROWS LAST_ANALYZED
---------- --------------------
     10000 2017-10-08 16:04:16


但是由于cascade=false,因此不会自动采集索引,

SQL> select num_rows, sample_size, to_char(last_analyzed,'yyyy-mm-dd hh24:mi:ss') last_analyzed from user_indexes where table_name='TEST';
  NUM_ROWS SAMPLE_SIZE LAST_ANALYZED
---------- ----------- -----------------------------
     10000          10000 2017-10-08 15:55:42


以cascade=true采集统计信息,表和索引的统计信息更新了,

SQL> exec dbms_stats.gather_table_stats('BISAL','TEST',cascade=>true);
PL/SQL procedure successfully completed.


SQL> select num_rows, to_char(last_analyzed,'yyyy-mm-dd hh24:mi:ss') last_analyzed from user_tables where table_name='TEST';
  NUM_ROWS LAST_ANALYZED
---------- --------------------
     10000 2017-10-08 16:07:18

SQL> select num_rows, sample_size, to_char(last_analyzed,'yyyy-mm-dd hh24:mi:ss') last_analyzed from user_indexes where table_name='TEST';
  NUM_ROWS SAMPLE_SIZE LAST_ANALYZED
---------- ----------- ---------------
     10000          10000 2017-10-08 16:07:18


此时执行truncate,清空表数据,

SQL> truncate table test;
Table truncated.

SQL> select count(*) from test;
  COUNT(*)
----------
     0


可以看出表和索引统计信息,没有被删除,

SQL> select num_rows, to_char(last_analyzed,'yyyy-mm-dd hh24:mi:ss') last_analyzed from user_tables where table_name='TEST';
  NUM_ROWS LAST_ANALYZED
---------- --------------------
     10000 2017-10-08 16:07:18

SQL> select num_rows, sample_size, to_char(last_analyzed,'yyyy-mm-dd hh24:mi:ss') last_analyzed from user_indexes where table_name='TEST';
  NUM_ROWS SAMPLE_SIZE LAST_ANALYZED
---------- ----------- ---------------
     10000          10000 2017-10-08 16:07:18


执行一次统计信息采集,此时表和索引的统计信息,已经是最新了,

SQL> exec dbms_stats.gather_table_stats('BISAL','TEST',cascade=>true);
PL/SQL procedure successfully completed.

SQL> select num_rows, to_char(last_analyzed,'yyyy-mm-dd hh24:mi:ss') last_analyzed from user_tables where table_name='TEST';
NUM_ROWS  LAST_ANALYZED
--------- --------------------
       0  2017-10-08 16:25:06

SQL> select num_rows, sample_size, to_char(last_analyzed,'yyyy-mm-dd hh24:mi:ss') last_analyzed from user_indexes where table_name='TEST';
  NUM_ROWS SAMPLE_SIZE LAST_ANALYZED
---------- ----------- --------------------
           0              0 2017-10-08 16:25:06


说明执行truncate,表的统计信息不会被删除,除非执行了统计信息采集,truncate table和表和索引的统计信息,没有任何关联。


另一方面,truncate会影响表是否可以被自动采集统计信息的任务触发,mon_mods_all$会记录自上次自动统计信息收集作业完成之后,对所有目标表的insert、delete和update操作所影响的记录数,即DML操作次数,以及目标表是否执行过truncate操作,主要用于每日统计信息采集作业判断是否需要采集此张表,对于这张视图mon_mods_all$的介绍,可以参考eygle的文章,

http://www.eygle.com/archives/2009/09/mon_mods_is_use.html


比如如下表,记录数为10000,mon_mods_all$记录了一条信息,其中插入insert是10000,其他的字段,为空,

SQL> select count(*) from test;
  COUNT(*)
----------
     10000


SQL> exec dbms_stats.flush_database_monitoring_info();
PL/SQL procedure successfully completed.

SQL> select obj#, inserts, updates, deletes, flags from sys.mon_mods_all$ where obj#=18021;
  OBJ#   INSERTS      UPDATES   DELETES   FLAGS
------ --------- --------- ---------- -------
 18021      10000            0          0       0


此时执行truncate,mon_mods_all$记录未变,

SQL> truncate table test;
Table truncated.

SQL> select obj#, inserts, updates, deletes, flags from sys.mon_mods_all$ where obj#=18021;
   OBJ#   INSERTS        UPDATES   DELETES    FLAGS
------- ---------- ---------- --------- --------
  18021        10000           0            0        0


此时执行一次dbms_stats.flush_database_monitoring_info(),显示FLAGS是1,表示执行过了truncate table,

SQL> exec dbms_stats.flush_database_monitoring_info();
PL/SQL procedure successfully completed.

SQL> select obj#, inserts, updates, deletes, flags from sys.mon_mods_all$ where obj#=18021;
   OBJ#   INSERTS        UPDATES   DELETES    FLAGS
------- ---------- ---------- --------- --------
  18021        10000           0         10000        1


再次执行统计信息采集,此时mon_mods_all$的记录就会被清空,

SQL> exec dbms_stats.gather_table_stats('BISAL','TEST',cascade=>true);
PL/SQL procedure successfully completed.

SQL> select obj#, inserts, updates, deletes, flags from sys.mon_mods_all$ where obj#=18021;
no rows selected



总结:

1. 执行truncate,表的统计信息不会被删除,除非执行了统计信息采集,truncate table和表和索引的统计信息,没有任何关联,对象是否有统计信息记录,取决于是否采集过统计信息,包括手工和自动两种方法。

2. 执行truncate,会将mon_mods_all$视图的FLAGS字段置位,变为1,自动采集统计信息作业,可以据此判断,是否需要采集这张表,当重新采集统计信息,就会删除mon_mods_all$保存的记录。



如果您觉得此篇文章对您有帮助,欢迎关注微信公众号:bisal的个人杂货铺,您的支持是对我最大的鼓励!共同学习,共同进步:)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325642170&siteId=291194637