Q 質問 更新主体のデータベース・システムなのですが,データ量が急激に増えていないにもかかわらず,データベースの応答性能が劣化しました。どんな原因が考えられ,どうすれば解消できるか教えてください。
A 回答 データの断片化などでI/O性能が劣化したと考えられます。テーブルやインデックスを再編成しましょう。

「稼働後数カ月たって徐々にI/O性能が悪化する」という場合には,その間に変化したものに着目すべきです。RDBMSでは時間の経過と共にデータ量が増減し,データの格納状態が変化します。データ量が増えれば処理しなければならないレコード数が増え,実行性能が悪くなることがあります。また,データベース・バッファなどの利用状況が変わり,I/O性能に影響を与えることもあります。
ご質問のシステムでは「データ量は急激に増えていない」ということなので,データの格納状態の変化が実行性能に影響を与えたと考えられます。テーブルやインデックスは更新を繰り返すとディスク上のデータの格納状態が悪化します。データは断片化(フラグメンテーション)し,Bツリー・インデックスのバランスが崩れてきます。こうなると,たとえデータ量が増えていなくても,ディスクI/Oが増えることがあります。ディスクI/Oが増えれば実行性能が悪化します。これらは更新主体のシステムで起きやすく,徐々にI/O性能を劣化させます。
更新の蓄積でディスクI/Oが増加
テーブルのレコードを削除すると,そのレコードがあったディスク上の領域は空き領域になります。レコードを更新する場合,更新前の領域に収まらなければ新しい領域に書き込み,元の領域は空き領域になります。RDBMS製品によっては上書きできるにもかかわらず上書きしない「追記型」の領域管理を行う製品もあります。
カットオーバー直後はディスク領域が整然としていても,更新の多いシステムではディスク上に空き領域が増え,データの断片化が進行します。データの断片化が進むと,無駄なディスク領域が必要になるだけでなく,実行性能にも悪影響を与えます。
図1[拡大表示]は,データの断片化の様子を示しています。1万レコードのテーブルAは当初は250ブロックで収まっていましたが,更新を繰り返してデータが断片化したため,レコード数が変わらないにもかかわらず,ブロック数が300に増えています。テーブルAの全件検索処理を考えた時,同じ処理にもかかわらず,50ブロック分ディスクI/Oが増え,実行性能が低下します。
更新を繰り返してデータの格納状態が悪化するのは,Bツリー・インデックスも同じです。Bツリー・インデックスは親ノードを中心にバランスよくデータを格納しようとしますが,更新を繰り返すとバランスが崩れ,ノードの階層が深くなることがあります。Bツリー・インデックスのノードの階層が深くなれば,それだけディスクI/Oが増えることになります(図2[拡大表示])。/
テーブルの再編成で断片化を解消
![]() |
図2●データの更新を繰り返すとインデックスのバランスが崩れ,I/O性能が劣化する 更新処理の多いデータベースでは,時間の経過と共にインデックスのノードのバランスが崩れ,ノードの深さが深くなる。インデックスのノードが深くなるとディスクI/Oが増え,I/O性能が劣化する。インデックスのバランスを元に戻すには,インデックスの再編成を行えば良い |
データの断片化を起こさないようにするために,各ブロックに空き領域を用意する方法があります。例えばOracleでは,ブロックの空き領域の割合を設定する「PCTFREE」や,空き領域を再利用する際の割合を設定する「PCTUSED」などのパラメータ値によって空き領域を制御できます。アプリケーションの特性などを考慮すれば,空き領域を十分にとっておくことで,できるだけデータの断片化が起きないようにすることは可能です。しかし更新主体のシステムにおいて,データの断片化を完全に防ぐことはできないでしょう。
データの断片化やインデックスのバランスの崩れを解消するには,それらを再編成することです。テーブルやインデックスの再編成とは,ディスク上のデータを整然と並べ直す処理のことです。Oracleのテーブルの再編成は,EXPORT/IMPORTコマンドを使います。テーブルのデータをディスクから取り出し(EXPORT),テーブルを削除し,ディスク上に整然と並べ直します(IMPORT)。インデックスの再編成は,インデックスを削除して作り直す処理になります。オンライン処理中に再編成処理が実施できるRDBMS製品もありますが,多くのRDBMS製品ではシステムを停止して実施する必要があります。