[Oracle] XXX_TABLES の AVG_ROW_LEN の値がおかしい! | Archive Redo Blog

Archive Redo Blog

DBエンジニアのあれこれ備忘録

Oracle では統計情報を適切に収集していれば、データ・ディクショナリ・ビュー XXX_TABLES の情報からテーブルのサイズを計算することができます。

実際のサイズは BLOCKS(使用済ブロック数)+EMPTY_BLOCKS(空きブロック数)から計算できます。

本当に必要なサイズは NUM_ROWS(行数)や AVG_ROW_LEN(1行あたりの平均バイト数)から見積もることができます。
(より正確に見積もるにはブロックサイズや各種オーバーヘッドを考慮する必要がありますが...)

実際のサイズと見積もりサイズを比較すれば、領域使用率を知ることもできます。


これらの情報を利用すれば、例えば、定期的にテーブルの領域使用率を監視し、使用率が一定の閾値を下回る場合にテーブルを再構築してテーブルを縮小するとともに、空き領域を増やすというような運用を行うことができるわけです。


ところが、先日、あるシステムで問題が発生しました。

実際には少なくとも領域使用率が 80% 以上はあると思われるテーブルの領域使用率がわずか 数% と計算されてしまい、テーブルの再構築が実行されてしまったのです。


調べてみると、どうも見積もりサイズが著しく小さく計算されているようです。

詳しく調べてみると、見積もりサイズの計算根拠となる AVG_ROW_LEN の値が著しく小さいことがわかりました。

さらに詳しく調べてみると、統計情報を収集するコマンドによって AVG_ROW_LEN の値が異なるようです。

ANALYZE TABLE <tablename> COMPUTE STATISTICS;
とすると正常(と思われる)値となり、

CALL DBMS_STATS.GATHER_TABLE_STATS('<ownername>','<tablename>');
とすると著しく小さな値となるようです。


どうもバグくさいと思って、サポートサイトを検索すると、やはり、バグでした。

LONG 列や LOB 列を持つテーブルに対して、DBMS_STATS.GATHER_XXXXXX_STATS プロシージャを使用して統計情報を収集すると、LONG 列や LOB 列のサイズを考慮せずに AVG_ROW_LEN の値を計算してしまうようです。

実際、問題が発生したテーブルには LOB 列が存在しました...

しかも、問題が発生したのは、9.2.0.x なんですが、このバグは 10.2.0 でしか改修されないようです...