Oracle表分析


Oracle表分析


當表沒有做分析的時候,Oracle 會使用動態采樣來收集統計信息。 獲取准確的段對象(表,表分區,索引等)的分析數據,是CBO存在的基石,CBO的機制就是收集盡可能多的對象信息和系統信息,通過對這些信息進行計算,分析,評估,最終得出一個成本最低的執行計划。所以對於CBO,數據段的分析就非常重要。

分析SQL

analyze table tablename compute statistics
等同於
analyze table tablename compute statistics for table for all indexes for all columns
for table的統計信息存在於視圖:user_tables 、all_tables、dba_tables
for allindexes的統計信息存在於視圖: user_indexes 、all_indexes、dba_indexes
for allcolumns的統計信息存在於試圖:user_tab_columns、all_tab_columns、dba_tab_columns

或者

SQL> exec dbms_stats.gather_table_stats(user,'xiaogongjiang');

生成的統計信息會存在於user_tables這個視圖,查看一下

select * from user_tables where table_name=table_name;

觀察一下NUM_ROWS,BLOCKS,AVG_SPACE,AVG_ROW_LEN幾列你就會明白,這就是變化。

刪除SQL
analyze table tablename delete statistics 會刪除所有的statistics
作用
Oracle分析表的作用:為了使基於CBO的執行計划更加准確

數據准備

Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.4.0
Connected as xx@xgj

SQL> create table xiaogongjiang as select a.OBJECT_ID ,a.OBJECT_NAME from dba_objects a ;--創建表

Table created

SQL> select count(1) from xiaogongjiang;

COUNT(1)
----------
35183

SQL> create index idx_object_id on xiaogongjiang(object_id);--在object_id建立索引

Index created

SQL>


分析前的數據及執行計划

SQL> select num_rows, avg_row_len, blocks, last_analyzed from user_tables where table_name = 'XIAOGONGJIANG';--表的信息

NUM_ROWS AVG_ROW_LEN BLOCKS LAST_ANALYZED
---------- ----------- ---------- -------------


SQL> select blevel,leaf_blocks,distinct_keys,last_analyzed from user_indexes where table_name='XIAOGONGJIANG';--索引信息

BLEVEL LEAF_BLOCKS DISTINCT_KEYS LAST_ANALYZED
---------- ----------- ------------- -------------

從查詢結果看出,表的行數,行長,占用的數據塊數及最后的分析時間都是空。 索引的相關信息也沒有,說明這個表和說因都沒有被分析,如果此時有一條SQL 對表做查詢,CBO 由於無法獲取這些信息,很可能生成錯誤的執行計划。
查詢執行計划
--執行sql,以便存到shared pool中
SQL>select /*+dynamic_sampling(xiaogongjiang 0) */ * from XIAOGONGJIANG where object_id>30;
.....省略輸出

-- 查詢出上個執行腳本對應的sql_id:5h16pnkvs0r5z
SQL>select * from v$sql a where a.SQL_TEXT like '%select /*+dynamic_sampling(xiaogongjiang 0) */ * from XIAOGONGJIANG where object_id>30%';
.....省略輸出

--使用dbms_xplan.display_cursor查看sql真正的執行計划
SQL>select * from table(dbms_xplan.display_cursor('5h16pnkvs0r5z'));

導出html,查看如下

 

 

 

在Oracle 10g以后,如果一個表沒有做分析,數據庫將自動對它做動態采樣分析,

所以這里采用hint的方式將動態采樣的級別設置為0,即不使用動態采樣。

分析后的數據及執行計划
第一種方式
SQL> analyze table xiaogongjiang compute statistics ;

Table analyzed

第二種方式(推薦)
SQL> exec dbms_stats.gather_table_stats(user,'xiaogongjiang');

PL/SQL procedure successfully completed

SQL> 第一個參數為用戶,第二個參數為表

通過DBMS_STATS包來分析,從9i 開始,Oracle 推薦使用DBMS_STATS包對表進行分析操作,因為DBMS_STATS 提供了更多的功能,以及靈活的操作方式。

SQL> select num_rows, avg_row_len, blocks, last_analyzed from user_tables where table_name = 'XIAOGONGJIANG';

NUM_ROWS AVG_ROW_LEN BLOCKS LAST_ANALYZED
---------- ----------- ---------- -------------
35183 27 152 2016-12-02 0:


SQL> select blevel,leaf_blocks,distinct_keys,last_analyzed from user_indexes where table_name='XIAOGONGJIANG';

BLEVEL LEAF_BLOCKS DISTINCT_KEYS LAST_ANALYZED
---------- ----------- ------------- -------------
1 77 35180 2016-12-02 0:

從上面的結果,可以看出DBMS_STATS.gather_table_stats已經對表和索引都做了分析。 現在我們在來看一下執行計划。

SQL>select * from xiaogongjiang where object_id>30;

SQL>select * from v$sql a where a.SQL_TEXT like '%select * from xiaogongjiang where object_id>30%';

SQL>select * from table(dbms_xplan.display_cursor('gzspgs4btcpuf'));

從這個計划,我們看出CBO 估算出的結果是35153條記錄,與實際的35183很近。 此時選擇全表掃描更優。 通過這個例子,我們也看出了分析對執行計划的重要性。

 

 由於Oracle的優化器是CBO,所以對象的統計數據對執行計划的生成至關重要!
 
 作用:DBMS_STATS.GATHER_TABLE_STATS統計表,列,索引的統計信息(默認參數下是對表進行直方圖信息收集,包含該表的自身-表的行數、數據塊數、行長等信息;列的分析--列值的重復數、列上的空值、數據在列上的分布情況;索引的分析-索引頁塊的數量、索引的深度、索引聚合因子).

 

DBMS_STATS.GATHER_TABLE_STATS的語法如下:

DBMS_STATS.GATHER_TABLE_STATS (   ownname          VARCHAR2,     tabname          VARCHAR2,     partname         VARCHAR2,   estimate_percent NUMBER,     block_sample     BOOLEAN,   method_opt       VARCHAR2,   degree           NUMBER,   granularity      VARCHAR2,     cascade          BOOLEAN,   stattab          VARCHAR2,     statid           VARCHAR2,   statown          VARCHAR2,   no_invalidate    BOOLEAN,   force            BOOLEAN);

參數說明:

ownname:要分析表的擁有者

tabname:要分析的表名.

partname:分區的名字,只對分區表或分區索引有用.

estimate_percent:采樣行的百分比,取值范圍[0.000001,100],null為全部分析,不采樣. 常量:DBMS_STATS.AUTO_SAMPLE_SIZE是默認值,由oracle決定最佳取采樣值.

block_sapmple:是否用塊采樣代替行采樣.

method_opt:決定histograms信息是怎樣被統計的.method_opt的取值如下(默認值為FOR ALL COLUMNS SIZE AUTO):

for all columns:統計所有列的histograms.

for all indexed columns:統計所有indexed列的histograms.

for all hidden columns:統計你看不到列的histograms

for columns <list> SIZE <N> | REPEAT | AUTO | SKEWONLY:統計指定列的histograms.N的取值范圍[1,254]; REPEAT上次統計過的histograms;AUTO由oracle決定N的大小;SKEWONLY multiple end-points with the same value which is what we define by "there is skew in thedata

degree:決定並行度.默認值為null.

granularity:Granularity of statistics to collect ,only pertinent if the table is partitioned.

cascade:是收集索引的信息.默認為FALSE.

stattab:指定要存儲統計信息的表,statid如果多個表的統計信息存儲在同一個stattab中用於進行區分.statown存儲統計信息表的擁有者.以上三個參數若不指定,統計信息會直接更新到數據字典.

no_invalidate: Does not invalidate the dependent cursors if set to TRUE. The procedure invalidates the dependent cursors immediately if set to FALSE.

force:即使表鎖住了也收集統計信息.

例子:

execute dbms_stats.gather_table_stats(ownname => 'owner',tabname => 'table_name' ,estimate_percent => null ,method_opt => 'for all indexed columns' ,cascade => true);

------------------------------------------------------------------------------------------------------------------------

自從Oracle8.1.5引入dbms_stats包,Experts們便推薦使用dbms_stats取代analyze。 理由如下
dbms_stats可以並行分析
dbms_stats有自動分析的功能(alter table monitor )
analyze 分析統計信息的不准確some times
1,2好理解,且第2點實際上在VLDB中是最吸引人的;3以前比較模糊,看了metalink236935.1 解釋,analyze在分析Partition表的時候,有時候會計算出不准確的Global statistics .
原因是,dbms_stats會實在的去分析表全局統計信息(當指定參數);而analyze是將表分區(局部)的statistics 匯總計算成表全局statistics ,可能導致誤差。
如果想分析整個用戶或數據庫,還可以采用工具包,可以並行分析
Dbms_utility(8i以前的工具包)
Dbms_stats(8i以后提供的工具包)

dbms_stats.gather_schema_stats(User,estimate_percent=>100,cascade=> TRUE);
dbms_stats.gather_table_stats(User,TableName,degree => 4,cascade => true);

如何使用dbms_stats分析統計信息?
--創建統計信息歷史保留表 

sql> exec dbms_stats.create_stat_table(ownname => 'scott',stattab => 'stat_table') ; 


--導出整個scheme的統計信息 

sql> exec dbms_stats.export_schema_stats(ownname => 'scott',stattab => 'stat_table') ; 


--分析scheme

Exec dbms_stats.gather_schema_stats( 
ownname => 'scott', 
options => 'GATHER AUTO', 
estimate_percent => dbms_stats.auto_sample_size, 
method_opt => 'for all indexed columns ', 
degree => 6 ) 


--分析表

sql> exec dbms_stats.gather_table_stats(ownname => 'scott',tabname => 'work_list',estimate_percent => 10,method_opt=> 'for all indexed columns') ; 


--分析索引

SQL> exec dbms_stats.gather_index_stats(ownname => 'crm2',indname => 'IDX_ADM_PERMISSION_PID_MID',estimate_percent => '10',degree => '4') ;


--如果發現執行計划走錯,刪除表的統計信息

SQL>dbms_stats.delete_table_stats(ownname => 'scott',tabname => 'work_list') ;


--導入表的歷史統計信息

sql> exec dbms_stats.import_table_stats(ownname => 'scott',tabname => 'work_list',stattab => 'stat_table') ; 


--如果進行分析后,大部分表的執行計划都走錯,需要導回整個scheme的統計信息

sql> exec dbms_stats.import_schema_stats(ownname => 'scott',stattab => 'stat_table');


--導入索引的統計信息

SQL> exec dbms_stats.import_index_stats(ownname => 'crm2',indname => 'IDX_ADM_PERMISSION_PID_MID',stattab => 'stat_table') 


--檢查是否導入成功

SQL> select table_name,num_rows,a.blocks,a.last_analyzed from all_tables a where a.table_name='WORK_LIST'; 


分析數據庫(包括所有的用戶對象和系統對象):gather_database_stats 
分析用戶所有的對象(包括表、索引、簇):gather_schema_stats
分析表:gather_table_stats
分析索引:gather_index_stats 
刪除數據庫統計信息:delete_database_stats
刪除用戶方案統計信息:delete_schema_stats
刪除表統計信息:delete_table_stats 
刪除索引統計信息:delete_index_stats
刪除列統計信息:delete_column_stats 
設置表統計信息:set_table_stats
設置索引統計信息:set_index_stats
設置列統計信息:set_column_stats 

可以查看表 DBA_TABLES來查看表是否與被分析過,如:

SELECT TABLE_NAME, LAST_ANALYZED FROM DBA_TABLES

 

這是對命令與工具包的一些總結
1、對於分區表,建議使用DBMS_STATS,而不是使用Analyze語句。
a) 可以並行進行,對多個用戶,多個Table
b) 可以得到整個分區表的數據和單個分區的數據。
c) 可以在不同級別上Compute Statistics:單個分區,子分區,全表,所有分區
d) 可以倒出統計信息
e) 可以用戶自動收集統計信息
2、DBMS_STATS的缺點
a) 不能Validate Structure
b) 不能收集CHAINED ROWS, 不能收集CLUSTER TABLE的信息,這兩個仍舊需要使用Analyze語句。
c) DBMS_STATS 默認不對索引進行Analyze,因為默認Cascade是False,需要手工指定為True
3、對於oracle 9里面的External Table,Analyze不能使用,只能使用DBMS_STATS來收集信息。

 

https://blog.csdn.net/yangshangwei/article/details/53428259

https://www.cnblogs.com/wbzhao/archive/2012/04/05/2433616.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM