今回は行移行と行連鎖のの確認を実際のデータを用いて確認してみます。

SQL> set lines 150 pages 500
SQL> col TABLE_NAME for a12
SQL> select TABLE_NAME, NUM_ROWS, BLOCKS, EMPTY_BLOCKS, CHAIN_CNT, AVG_ROW_LEN
  2  from USER_TABLES
  3  where TABLE_NAME = 'TAB1_1' ;

TABLE_NAME     NUM_ROWS     BLOCKS EMPTY_BLOCKS  CHAIN_CNT AVG_ROW_LEN
------------ ---------- ---------- ------------ ---------- -----------
TAB1_1             1000          5            0          0          19


行連鎖、行移行の確認は統計情報が更新されていればUSER_TABLES表で確認することが出来ます。

SQL> @?/rdbms/admin/utlchain.sql

表が作成されました。

SQL> desc CHAINED_ROWS
 名前                                                                                                            NULL?    型
 -------------------------------------------------------------------------------                              ---- -------- --------------------------------------------------------
 OWNER_NAME                                                                                                                 VARCHAR2(30)
 TABLE_NAME                                                                                                                 VARCHAR2(30)
 CLUSTER_NAME                                                                                                               VARCHAR2(30)
 PARTITION_NAME                                                                                                             VARCHAR2(30)
 SUBPARTITION_NAME                                                                                                          VARCHAR2(30)
 HEAD_ROWID                                                                                                                 ROWID
 ANALYZE_TIMESTAMP                                                                                                          DATE


また、utlchain.sqlで作成される、CHAINED_ROWS表からも確認することが出来ます。

SQL> analyze table TAB1_1 list chained rows;

表が分析されました。

SQL> select TABLE_NAME, HEAD_ROWID from CHAINED_ROWS ;

レコードが選択されませんでした。

 
analyse文を表に対して実行することで、その表が行移行・行連鎖をしているかをわかります。

SQL> set lines 150 pages 500
SQL> set autot on
SQL> select ROWID, COL1, substr(COL2,1,10) from TAB1_1 where COL1=500;

ROWID                    COL1 SUBSTR(COL2,1,10)
------------------ ---------- ----------------------------------------
AAATkZAAAAAAACDADB        500 initial Re


実行計画
----------------------------------------------------------
Plan hash value: 3998103940

-----------------------------------------------------------------------------------------
| Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |           |     1 |    19 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TAB1_1    |     1 |    19 |     2   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | PK_TAB1_1 |     1 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("COL1"=500)


統計
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
        719  bytes sent via SQL*Net to client
        519  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed


一件のデータのみが出力されるSQL文を実行します。
「consistent gets」で確認できるのが読み込んだデータブロックの数です。

SQL> update TAB1_1 set COL2=rpad('updated', 4000, '*') where COL1=500 ;

1行が更新されました。

SQL> commit ;

コミットが完了しました。

SQL> analyze table TAB1_1 list chained rows;

表が分析されました。

SQL> select TABLE_NAME, HEAD_ROWID from CHAINED_ROWS ;

TABLE_NAME                     HEAD_ROWID
------------------------------ ------------------
TAB1_1                         AAATkZAAAAAAACDADB


先ほどSELECTした行を更新して、4000バイトの文字列を設定します。
これで、4Kのブロックが溢れて、ROWIDを記したヘッダを残し、データは新しいブロックに移行しました。
これが行移行です。

SQL> set lines 150 pages 500
SQL> set autot on
SQL> select ROWID, COL1, substr(COL2, 1, 10) from TAB1_1 where COL1=500 ;

ROWID                    COL1 SUBSTR(COL2,1,10)
------------------ ---------- ----------------------------------------
AAATkZAAAAAAACDADB        500 updated***


実行計画
----------------------------------------------------------
Plan hash value: 3998103940

-----------------------------------------------------------------------------------------
| Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |           |     1 |    19 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TAB1_1    |     1 |    19 |     2   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | PK_TAB1_1 |     1 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("COL1"=500)


統計
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          4  consistent gets
          0  physical reads
          0  redo size
        719  bytes sent via SQL*Net to client
        520  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed


「consistent gets」からも取得するブロック数が+1なっていることがわかります。
ヘッダの分と実データの分です。