行連鎖と行移行

行連鎖*1

行連鎖とは
データ挿入時に発生する現象
行連鎖とは 1 レコードの実サイズがデータブロックのデータ領域を超える場合(LONGを使用しているなど)に発生する。
データは 1 ブロックに収まらずに、2 つ以上の行断片(レコードピース)に分割して格納される。 行連鎖による行断片の連鎖の状態は、行ディレクトリに連鎖先のROWIDを格納する一方向の線形リストで管理されている。
行連鎖が発生したレコードの読み込みに最低 2 ブロック必要になるので効率が悪く、 データブロックサイズを大きくすること(またはテーブル分割)を検討する。

行移行*2

行移行とは
データ更新時に発生する現象
行移行とは、データレコードを更新するときにブロック内の空き領域を使用してもデータブロック内に収まらず 実データの行断片(レコードピース)を、すべて、別のデータブロックへ引越している状態をさす。
移行先の ROWID を行ディレクトリに格納する線形リストで管理している。
※ 行移行は完全な移動ではないので ROWID は変更されていない点がポイント。
ROWID が変更されると、テーブル所有のすべてのインデックスの ROWID を更新しなければならない。
そのためテーブルのデータの更新だけに比べての数倍のコストが必要になる。
ROW MOVEMENT 指定によりパーティション移動を伴う更新の場合には格納先と同時に ROWID も変更される。
(インデックスの更新は、データの更新にくらべて、およそインデックス数 × 2 のコストが余計に必要)
行移行が発生しているレコードの読み込みに最低 2 ブロック必要になるので効率が悪い
空き領域は テーブルの PCTFREE (PCTUSED) パラメータ で管理されているので、そのチューニングを検討する。

行連鎖と行移行*3

表の行データが1つのデータ・ブロック内に収まらない状況が2つあります。1番目の状況は、行を最初に挿入するときに、その行が大きすぎて1つのデータ・ブロック内に収まらない場合です。このような場合、Oracleはその行のデータを、そのセグメント用に確保されたデータ・ブロックの連鎖(1つ以上)に格納します。行連鎖は、データ型LONGまたはLONG RAWの列が入っている行など、大きな行で最も頻繁に発生します。そのような場合の行連鎖は、避けられません。

それに対して、2番目の状況は、1つのデータ・ブロック内にすでに収まっていた行が更新されて、行全体の長さが増加したが、ブロックの空き領域がすでにいっぱいになっている場合です。この場合、Oracleはその行全体のデータを新しいデータ・ブロックに移行します(その行全体が新しいブロックに収まる場合)。移行された行の元の行断片は、行の移行先の新しいブロックを指すように保たれます。そのため、移動された行のROWIDは変わりません。

行が連鎖または移行されると、その行に関連するI/Oパフォーマンスは低下します。これは、その行の情報を取り出す際に、Oracleが複数のデータ・ブロックをスキャンする必要があるためです。