dba_tables中的avg_row_len是如何被計算的?

kunlunzhiying發表於2017-10-30
收集資訊時avg_row_len被計算,使用analyze 和dbms_stats蒐集時計算avg_row_len的差別在於後者不考慮row header佔用的3個byte

doc如下:

C:>sqlplus xys/manager

SQL*Plus: Release 10.2.0.1.0 - Production on 星期一 10月 8 22:10:18 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.


連線到:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> desc tab1;
名稱 是否為空? 型別
----------------------------------------- -------- ----------------------------

ID NUMBER(38)
NAME VARCHAR2(10)
TIME DATE

SQL> select avg_row_len from user_tables where table_name='TAB1';

AVG_ROW_LEN
-----------
16

SQL> SELECT *FROM TAB1;

ID NAME TIME
---------- ---------- --------------
1 a 08-10月-07

SQL> insert into tab1 values(2,null , sysdate);

已建立 1 行。

SQL> commit;

提交完成。

SQL> analyze table tab1 compute statistics;

表已分析。

SQL> select avg_row_len from user_tables where table_name='TAB1';

AVG_ROW_LEN
-----------
15

SQL> select * from tab1;

ID NAME TIME
---------- ---------- --------------
1 a 08-10月-07
2 08-10月-07
--這裡的3是row header佔用的byte,1代表的是The column length requires 1 byte for columns that store 250 bytes or less

SQL> select 3+vsize(id)+1+vsize(name)+1+vsize(time)+1 from tab1;

3+VSIZE(ID)+1+VSIZE(NAME)+1+VSIZE(TIME)+1
-----------------------------------------
16


SQL> select 3+vsize(id)+1+nvl(vsize(name),0)+1+vsize(time)+1 from tab1;

3+VSIZE(ID)+1+NVL(VSIZE(NAME),0)+1+VSIZE(TIME)+1
------------------------------------------------
16
15

SQL> truncate table tab1;

表被截斷。

SQL> insert into tab1 values(2,null , sysdate);

已建立 1 行。

SQL> commit;

提交完成。

SQL> analyze table tab1 compute statistics;

表已分析。

SQL> select avg_row_len from user_tables where table_name='TAB1';

AVG_ROW_LEN
-----------
15
--如果是null的話而且不在末尾,也就是不是最後一個欄位,那麼只有column len佔用一個位元組
SQL> select 3+vsize(id)+1+nvl(vsize(name),0)+1+vsize(time)+1 from tab1;

3+VSIZE(ID)+1+NVL(VSIZE(NAME),0)+1+VSIZE(TIME)+1
------------------------------------------------
15

SQL> truncate table tab1;

表被截斷。

SQL> insert into tab1 values(2,'a',null);

已建立 1 行。

SQL> commit;

提交完成。

SQL> analyze table tab1 compute statistics;

表已分析。

SQL> select avg_row_len from user_tables where table_name='TAB1';

AVG_ROW_LEN
-----------
8

SQL> select * from tab1;

ID NAME TIME
---------- ---------- --------------
2 a
--如果最後的欄位是null的話,那麼column len也不佔用位元組,也就是doc上提到的for trailing null columns Oracle does not even store the column length.
前幾天還看到有人問什麼是"trailing null columns",biti大師做了回答
SQL> select 3+vsize(id)+1+vsize(name)+1 from tab1;

3+VSIZE(ID)+1+VSIZE(NAME)+1
---------------------------
8

SQL> alter table tab1 add col1 varchar2(300);

表已更改。

SQL> analyze table tab1 compute statistics;

表已分析。

SQL> select avg_row_len from user_tables where table_name='TAB1';

AVG_ROW_LEN
-----------
8

SQL> update tab1 set col1=rpad('a' , 249);

已更新 1 行。

SQL> commit;

提交完成。

SQL> analyze table tab1 compute statistics;

表已分析。

SQL> select avg_row_len from user_tables where table_name='TAB1';

AVG_ROW_LEN
-----------
259

SQL> select id , name , time , substr(col1 , 1 , 1) from tab1;

ID NAME TIME SU
---------- ---------- -------------- --
2 a a

SQL> select 3+vsize(id)+1+vsize(name)+1+nvl(vsize(time),0)+1+1+vsize(col1) from
tab1;

3+VSIZE(ID)+1+VSIZE(NAME)+1+NVL(VSIZE(TIME),0)+1+1+VSIZE(COL1)
--------------------------------------------------------------
259

SQL> update tab1 set col1=rpad('a' , 250);

已更新 1 行。

SQL> commit;

提交完成。

SQL> analyze table tab1 compute statistics;

表已分析。

SQL> select avg_row_len from user_tables where table_name='TAB1';

AVG_ROW_LEN
-----------
260

SQL> select 3+vsize(id)+1+vsize(name)+1+nvl(vsize(time),0)+1+1+vsize(col1) from
tab1;

3+VSIZE(ID)+1+VSIZE(NAME)+1+NVL(VSIZE(TIME),0)+1+1+VSIZE(COL1)
--------------------------------------------------------------
260
--The column length requires 1 byte for columns that store 250 bytes or less, or 3 bytes for columns that store more than 250 bytes
當列上的值超過250的時候,column len要求3個byte
SQL> update tab1 set col1=rpad('a' , 251);

已更新 1 行。

SQL> commit;

提交完成。

SQL> analyze table tab1 compute statistics;

表已分析。

SQL> select avg_row_len from user_tables where table_name='TAB1';

AVG_ROW_LEN
-----------
263

SQL> select 3+vsize(id)+1+vsize(name)+1+nvl(vsize(time),0)+1+1+vsize(col1) from
tab1;

3+VSIZE(ID)+1+VSIZE(NAME)+1+NVL(VSIZE(TIME),0)+1+1+VSIZE(COL1)
--------------------------------------------------------------
261

SQL> select 3+vsize(id)+1+vsize(name)+1+nvl(vsize(time),0)+1+3+vsize(col1) from
tab1;

3+VSIZE(ID)+1+VSIZE(NAME)+1+NVL(VSIZE(TIME),0)+1+3+VSIZE(COL1)
--------------------------------------------------------------
263
--==============================================================================
使用dbms_stats收集statistics情況會有所不同,計算avg_row_len時row header不被計算
SQL> truncate table tab1;

表被截斷。

SQL> desc tab1;
名稱 是否為空? 型別
----------------------------------------- -------- ----------------------------

ID NUMBER(38)
NAME VARCHAR2(10)
TIME DATE
COL1 VARCHAR2(300)

SQL> insert into tab1(id , name) values(1 , 'a');

已建立 1 行。

SQL> commit;

提交完成。

SQL> exec dbms_stats.gather_table_stats('xys' , 'tab1');

PL/SQL 過程已成功完成。

SQL> select avg_row_len from user_tables where table_name='TAB1';

AVG_ROW_LEN
-----------
6

SQL> select vsize(id)+1+vsize(name)+1 from tab1;

VSIZE(ID)+1+VSIZE(NAME)+1
-------------------------
5

SQL> update tab1 set time=sysdate;

已更新 1 行。

SQL> commit;

提交完成。

SQL> exec dbms_stats.gather_table_stats('xys' , 'tab1');

PL/SQL 過程已成功完成。

SQL> select avg_row_len from user_tables where table_name='TAB1';

AVG_ROW_LEN
-----------
13

SQL> select vsize(id)+1+vsize(name)+1+vsize(time)+1 from tab1;

VSIZE(ID)+1+VSIZE(NAME)+1+VSIZE(TIME)+1
---------------------------------------
13

SQL> update tab1 set col1=rpad('a',249);

已更新 1 行。

SQL> commit;

提交完成。

SQL> exec dbms_stats.gather_table_stats('xys' , 'tab1');

PL/SQL 過程已成功完成。

SQL> select avg_row_len from user_tables where table_name='TAB1';

AVG_ROW_LEN
-----------
263

SQL> select vsize(id)+1+vsize(name)+1+vsize(time)+1+vsize(col1)+1 from tab1;

VSIZE(ID)+1+VSIZE(NAME)+1+VSIZE(TIME)+1+VSIZE(COL1)+1
-----------------------------------------------------
263

SQL> update tab1 set col1=rpad('a',250);

已更新 1 行。

SQL> commit;

提交完成。

SQL> exec dbms_stats.gather_table_stats('xys' , 'tab1');

PL/SQL 過程已成功完成。

SQL> select avg_row_len from user_tables where table_name='TAB1';

AVG_ROW_LEN
-----------
264

SQL> select vsize(id)+1+vsize(name)+1+vsize(time)+1+vsize(col1)+1 from tab1;

VSIZE(ID)+1+VSIZE(NAME)+1+VSIZE(TIME)+1+VSIZE(COL1)+1
-----------------------------------------------------
264

SQL> update tab1 set col1=rpad('a',251);

已更新 1 行。

SQL> commit;

提交完成。

SQL> exec dbms_stats.gather_table_stats('xys' , 'tab1');

PL/SQL 過程已成功完成。

SQL> select avg_row_len from user_tables where table_name='TAB1';

AVG_ROW_LEN
-----------
265

SQL> select vsize(id)+1+vsize(name)+1+vsize(time)+1+vsize(col1)+1 from tab1;

VSIZE(ID)+1+VSIZE(NAME)+1+VSIZE(TIME)+1+VSIZE(COL1)+1
-----------------------------------------------------
265

SQL>

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28211342/viewspace-2146596/,如需轉載,請註明出處,否則將追究法律責任。

相關文章