Sometimes, you need to modify the statistics of a table. There are various reasons: either for the performance analysis or because the execution plan changed. Oracle offers two methods: statistics restore or statistics export. Both are in the dbms_stats package.
1. Statistics restore
This method uses the procedure dbms_stats.restore_%_stats, where % can be table, schema, database, and fixed_objects.
This is an example for a restoration of a table with definite timestamp. The starting situation is:
Statistics info:
SQL> select table_name, num_rows,to_char(last_analyzed,'DD.MM.YYYY HH24:MI:SS')from dba_tables where owner ='SCHEMA1' and table_name='TAB1';TABLE_NAME NUM_ROWS LAST_ANALYZED ------------------------------ ------------- ------------------- TAB1 5 22.02.2011 10:20:07
Histograms info:
select table_name, column_name, count(*) from dba_histograms where owner='SCHEMA1' and table_name='TAB1' group by table_name, column_name;TABLE_NAME COLUMN_NAME COUNT(*) ----------------- -------------------- ---------- TAB1 ADRESS 2 TAB1 NAME 2 TAB1 NPA 2 TAB1 ID 2 TAB1 LOCALITE 2
Now, let’s remove the statistics:
exec DBMS_STATS.DELETE_TABLE_STATS(OWNNAME=>'SCHMEMA1', TABNAME=>'TAB1'); Procedure PL/SQL terminate with success.
Checking information:
SQL> select table_name,num_rows,to_char(last_analyzed,'DD.MM.YYYY HH24:MI:SS') from dba_tables where owner ='SCHEMA1' and table_name='TAB1';TABLE_NAME NUM_ROWS LAST_ANALYZED ------------------------------ ------------- ------------------- TAB1SQL> select table_name, column_name, count(*) 2 from dba_histograms 3 where owner='SCHEMA1' 4 and table_name='TAB1' 5 group by table_name, column_name;TABLE_NAME COLUMN_NAME COUNT(*) ---------------- -------------------- ---------- TAB1 ID 2
Now, let’s have a look which statistics are available:
select count(*), stats_update_time from dba_tab_stats_history where owner='SCHEMA1' and table_name='TAB1' group by stats_update_time; COUNT(*) STATS_UPDATE_TIME ------------- --------------------------------------------------------------------------- 1 11/02/11 21:00:47,054000 +01:00 1 22/02/11 10:20:07,587000 +01:00 1 22/02/11 10:25:12,524000 +01:00 9 rows selected.
Let’s try to restore the second line:
SQL> exec dbms_stats.restore_table_stats(ownname=>'SCHEMA1',tabname=>'TAB1',AS_OF_TIMESTAMP=>'22/02/11 10:20:07,587000 +01:00');Procedure PL/SQL terminate with success.
Now, I could check if the previous statistics were retrieved correctly:
SQL> select table_name, column_name, count(*) 2 from dba_histograms 3 where owner='SCHEMA1' 4 and table_name='TAB1' 5 group by table_name, column_name;TABLE_NAME COLUMN_NAME COUNT(*) ---------------- -------------------- ---------- TAB1 ADRESS 2 TAB1 NAME 2 TAB1 NPA 2 TAB1 ID 2 TAB1 LOCALITE 2 SQL> select table_name,num_rows,to_char(last_analyzed,'DD.MM.YYYY HH24:MI:SS') from dba_tables where owner ='SCHEMA1' and table_name='TAB1';TABLE_NAME NUM_ROWS LAST_ANALYZED ------------------------------ ------------- ------------------- TAB1 5 22.02.2011 10:20:07
The disadvantage with this method is knowing which timestamp should be restored. In the following case, the solution is allowed to put a tag. It is therefore easier to restore the desired statistics.
2. Statistics export
An alternative is to store the statistics in a table and associate it with a tag.
Here are the steps:
1) Create the statistics table
exec dbms_stats.create_stat_table('SCHEMA1','STATS');
2) Export the statistics
exec dbms_stats.export_table_stats('SCHEMA1','TAB1',NULL,'STATS','TAG1_TAB1',TRUE);This procedure could be also used to extract statistics from the production to feed that of the test.
3) Check statistics information
Statistics info:
SQL> select table_name, num_rows,to_char(last_analyzed,'DD.MM.YYYY HH24:MI:SS')from dba_tables where owner ='SCHEMA1' and table_name='TAB1';TABLE_NAME NUM_ROWS LAST_ANALYZED ------------------------------ ------------- ------------------- TAB1 5 22.02.2011 10:20:07
Histograms info:
select table_name, column_name, count(*) from dba_histograms where owner='SCHEMA1' and table_name='TAB1' group by table_name, column_name;TABLE_NAME COLUMN_NAME COUNT(*) ----------------- -------------------- ---------- TAB1 ADRESS 2 TAB1 NAME 2 TAB1 NPA 2 TAB1 ID 2 TAB1 LOCALITE 2
4) Delete statistics
exec DBMS_STATS.DELETE_TABLE_STATS(OWNNAME=>'SCHEMA1', TABNAME=>'TAB1');SQL> select table_name,num_rows,to_char(last_analyzed,'DD.MM.YYYY HH24:MI:SS') from dba_tables where owner ='SCHEMA1' and table_name='TAB1';TABLE_NAME NUM_ROWS LAST_ANALYZED ------------------------------ ------------- ------------------- TAB1
5) Import statistics
exec dbms_stats.import_table_stats('SCHEMA1','TAB1',NULL,'STATS','TAG1_TAB1',TRUE);
The statid parameter is allowed to store several evolutions of statistics and thus the capacity to go through the time.
Here the name is ‘TAG1_TAB1’, thus I could have ‘TAG2_TAB1’, ‘TAG3_TAB1’,.. too.
6) Check if statistics are corrects
SQL> select table_name,num_rows,to_char(last_analyzed,'DD.MM.YYYY HH24:MI:SS') from dba_tables where owner ='SCHEMA1' and table_name='TAB1';TABLE_NAME NUM_ROWS LAST_ANALYZED ------------------------------ ---------- ------------------- TAB1 5 22.02.2011 10:20:07
I will come back on this topic in another posting.