【Oracle】行連鎖と行移行の違いと対処法

【Oracle】行連鎖と行移行の違いと対処法

PR Amazonのアソシエイトとして、ITナレッジライフは適格販売により収入を得ています。

記事の文字数:3,615 / 総アクセス数:1 views

Oracleデータベースでパフォーマンス低下の原因となる「行連鎖(Row Chaining)」と「行移行(Row Migration)」の違い、原因、確認方法、そして対処法についてわかりやすく解説します。

Oracleユーザにお勧めの本 ↗

おすすめ

図解入門よくわかる 最新Oracleデータベースの基本と仕組み[第6版]

難易度
実用性
読みやすさ

図解が豊富で、概念的な理解に最適。実務に入る前の「全体像把握」に最適な一冊です。

絵で見てわかるOracleの仕組み 新装版

難易度
実用性
読みやすさ

プロとしてのOracle PL/SQL入門 【第3版】(Oracle 12c、11g、10g対応)

難易度
実用性
読みやすさ

PL/SQLの構文から実践的なテクニックまで網羅。現場でコードを書くなら手元に置きたい一冊です。

Oracleデータベースを運用していると、「最近なんとなくクエリのレスポンスが遅くなった」と感じることがあります。そのパフォーマンス低下の隠れた原因としてよく挙げられるのが 「行連鎖(Row Chaining)」「行移行(Row Migration)」 です。

どちらも、1行を取得する際に複数のブロックへのアクセスが必要になる場合があるという点では共通していますが、発生するメカニズムや根本的な原因、対処法には明確な違いがあります。

本記事では、oracle 行連鎖 行移行 違い のキーワードを軸に、それぞれの事象の概要と違い、そして具体的な対処法をわかりやすく解説します。

Oracleにおける行連鎖(Row Chaining)とは

行連鎖(Row Chaining) は、1行のデータサイズが大きすぎて、1つのデータブロック(Oracleがデータを格納する最小単位)に収まりきらない場合に発生します。

  • 発生タイミング: INSERT(挿入)時に発生するほか、UPDATE(更新)によって行が大きくなった場合にも発生することがあります。
  • 原因: 主に以下の2つの原因があります。
    1. データサイズがブロック容量を超える場合: 一般的なOracle Databaseでは8KBのブロックサイズが使用されますが、行ヘッダなどの領域も必要なため、1行のデータを1つのブロックに収めきれない場合に行連鎖が発生します。
    2. 255列を超える列を持つ場合(ブロック内行連鎖): Oracleの内部仕様として「1つの行断片(Row Piece)には最大255列までしか格納できない」という制限があります。そのため、256列以上の列を持つテーブルでは、たとえ1行全体のデータサイズが極めて小さくても必ず行が分割され、行連鎖が発生します。
  • 特徴: 1行のデータを格納するために、Oracleは複数のデータ断片をチェーン(鎖)のようにつないで分割保存します。巨大なサイズの列を持つテーブルだけでなく、非常に多くの列を持つテーブルでも構造上必ず発生する現象です。

Oracleにおける行移行(Row Migration)とは

行移行(Row Migration) は、最初は1つのブロックに収まっていたデータが、更新によってサイズが大きくなり、元のブロックに収まりきらなくなった場合に発生します。

  • 発生タイミング: データのUPDATE(更新)時
  • 原因: 更新(UPDATE)によってデータ長が増加し、現在のブロック内の空き領域(PCTFREE)では足りなくなったことが原因です。VARCHAR2型などを短い文字列から長い文字列に更新した際によく発生します。
  • 特徴: Oracleは、その行全体のデータを丸ごと別の新しいブロックへ「移行」させます。元のブロックには行の移動先を示す情報(ポインタ)が残され、ROWIDを利用してアクセスする場合に追加のブロックアクセスが必要になることがあります。

【Oracle】行連鎖と行移行の違いとは?原因と特徴を比較

行連鎖と行移行の違いをわかりやすく表にまとめました。

項目行連鎖 (Row Chaining)行移行 (Row Migration)
主な原因1行が1ブロックに収まらず、複数ブロックにまたがって格納されるUPDATEで行が大きくなり、元のブロックに収まらなくなる
発生契機INSERT時やUPDATE時などUPDATE時
データの状態1行が複数ブロックに分割されて格納される行全体が別ブロックへ移動し、元ブロックに移行先を示す情報が残る
アクセスへの影響複数ブロックへのアクセスが必要になる場合がある移行先ブロックへの追加アクセスが必要になる場合がある
主な対策行サイズ・表設計・LOB格納方式などの見直しMOVEなどの再編成、PCTFREEの見直し

どちらも、1行の取得に複数ブロックへのアクセスが必要になることで、ディスクI/Oや論理I/Oが増加し、アクセス性能に悪影響を与える可能性があります。

Oracleでの行連鎖と行移行の確認方法

テーブル内でどれくらいの行連鎖や行移行が発生しているかを確認するには、専用のテーブル(CHAINED_ROWS)へ出力する方法が一般的です。 実務では、オプティマイザ統計への影響を防ぎつつ確認を行えるため、「専用テーブル(CHAINED_ROWS)へ出力する方法」が適しています

[!WARNING]
DBMS_STATS による通常のオプティマイザ統計収集では CHAIN_CNT は収集されません。
標準的な統計情報の収集には DBMS_STATS が推奨されますが、この通常の統計収集処理では行連鎖・行移行の情報(CHAIN_CNT)を更新することはできません。CHAIN_CNTを確認する場合は、ANALYZE TABLE ... LIST CHAINED ROWS などの行連鎖・行移行の確認用機能を使用する必要があります。

専用テーブル(CHAINED_ROWS)に出力して確認する

オプティマイザ統計を収集・更新することなく、行移行・行連鎖が発生している行を特定し、その検出件数を確認できます。

1. 事前に結果を格納するテーブル(CHAINED_ROWS)を作成(初回のみ)

-- Oracle標準スクリプトを実行してテーブルを作成します
@?/rdbms/admin/utlchain.sql

2. 対象テーブルを解析して、移行・連鎖行をリストアップ

-- 以前の解析結果をクリア
DELETE FROM CHAINED_ROWS
WHERE OWNER_NAME = 'スキーマ名'
AND TABLE_NAME = 'テーブル名';
-- 対象テーブルの解析を実行(統計情報は書き換えません)
ANALYZE TABLE スキーマ名.テーブル名 LIST CHAINED ROWS;

3. 検出件数を確認

SELECT TABLE_NAME, COUNT(HEAD_ROWID) AS CHAINED_ROW_COUNT
FROM CHAINED_ROWS
WHERE OWNER_NAME = 'スキーマ名'
AND TABLE_NAME = 'テーブル名'
GROUP BY TABLE_NAME;
-- ※パーティション表の場合、CHAINED_ROWSには PARTITION_NAME 列もあるため、
-- SELECTとGROUP BYに含めることでパーティション単位での集計も可能です。

[!NOTE]

ANALYZE … COMPUTE STATISTICS について

簡易的にビュー(DBA_TABLES)の CHAIN_CNT 列を確認するために ANALYZE TABLE ... COMPUTE/ESTIMATE STATISTICS を実行する方法もありますが、現在のOracle Databaseでは 非推奨(obsolete) です。オプティマイザ統計情報が意図せず上書きされるリスクがあるため、行移行・連鎖の確認には ANALYZE TABLE ... LIST CHAINED ROWS を使用してください。

CHAINED_ROWS のカウントは ANALYZE 実行時点の値であり、行連鎖・行移行の発生状況を確認する目安になります。ただし、値が大きいからといって必ずしも即座に深刻な性能問題が発生しているとは限らないため、実際のSQLSQL [エスキューエル / シークエル]Structured Query Language。関係データベース(RDB)の管理や操作を行うデータベース言語の実行計画や論理I/O・物理I/Oなども併せて確認する必要があります。

Oracleの行連鎖と行移行の違いに合わせたそれぞれの対処法

それぞれ原因が異なるため、対処法も異なります。

行移行の対処法:テーブル再編成とPCTFREEの調整

行移行は、データが元のブロックから別のブロックへ引っ越してしまった状態です。これをもとに戻すには、テーブルの再編成が有効です。(※まずは検証環境で実施して、安全性や性能影響を確認することをおすすめします。)

  1. テーブルの移動(再編成)

    ALTER TABLE テーブル名 MOVE;
    -- ※通常のヒープ表では、MOVEによってROWIDが変わるため、関連するインデックスがUNUSABLEになる場合があります。`UPDATE INDEXES` などでインデックスを維持する方法もあります。
    ALTER INDEX インデックス名 REBUILD;
  2. PCTFREEの調整

    既存の行移行はMOVEで解消しますが、今後のUPDATEによる行移行を抑制するためには、テーブルの PCTFREE(将来の更新に備えて確保しておくブロック内の空き領域の割合)の値を大きく設定し直します。

    ALTER TABLE テーブル名 PCTFREE 20;

行連鎖の対処法:ブロックサイズの変更とテーブル設計見直し

行連鎖は「データが大きすぎてブロックに入らない」という物理的な制限によるものです。そのため、テーブルの再編成(MOVE)をしても根本的には解決しません。

  1. テーブル設計やLOB格納方式の見直し
    不要なカラムを別テーブルに切り出す(正規化)、LOB型の格納方式(インライン/アウトオブライン)を見直すなど、1行あたりのデータサイズを小さくするアプローチが第一選択となります。
  2. ブロックサイズの大きい表領域の検討
    行サイズが非常に大きく、通常のブロックサイズでは1行を収められないケースでは、より大きなブロックサイズの表領域を検討する方法もあります。ただし、ブロックサイズの変更はデータベース全体の設計にも関係するため、単純な行連鎖対策として安易に変更するのではなく、まずは上記の表設計の見直しなどを含めて総合的に検討する必要があります。

まとめ:Oracleの行連鎖と行移行の違いを理解して対処しよう

本記事では、Oracleにおける「行連鎖(Row Chaining)」と「行移行(Row Migration)」の違いについて解説しました。

  • 行連鎖: 1行が1ブロックに収まらず、複数ブロックにまたがって格納される
  • 行移行: 更新でデータが大きくなり、別のブロックに引っ越す(主にUPDATE時)

パフォーマンスチューニングを行う際は、どちらの事象が起きているのかを正しく見極め、適切なアプローチ(再編成やPCTFREEの変更、ブロックサイズの見直し)を選択することが重要です。

[!NOTE]

Oracle Databaseの使い方・設定まとめ

本記事の他にも、Oracle Databaseの実務で役立つ知識を多数紹介しています。あわせてご確認ください!

Oracle Database 使い方・設定まとめ
ITナレッジライフ

Oracle Database 使い方・設定まとめ

Oracle Databaseの使い方・設定まとめページ。Windowsへのインストール手順から、NVL・TRUNC等の必須関数、ROWNUM・UNIONの使い分けなど実務で役立つSQLの応用・チューニング手法まで、初心者から中級者向けに体系的に解説します。


以上で本記事の解説を終わります。
よいITライフを!
ITナレッジライフ 運営者
この記事を書いた人

Z (ITナレッジライフ)

現役のITエンジニア。Linux、プログラミング、IT用語など、日々の業務で得た「痒いところに手が届く」技術情報を発信しています。

プロフィールと編集ポリシーを見る

Oracleユーザにお勧めの本 ↗

おすすめ

図解入門よくわかる 最新Oracleデータベースの基本と仕組み[第6版]

難易度
実用性
読みやすさ

図解が豊富で、概念的な理解に最適。実務に入る前の「全体像把握」に最適な一冊です。

人気記事


記事を評価

Thanks!
目次
Scroll to Top