UPDATE処理が遅い原因はINDEX?パフォーマンス低下の仕組みを解説

  • URLをコピーしました!

UPDATE文の処理が急に遅くなり、「実行計画も問題なさそうなのに原因が分からない」という状況に遭遇した経験はないでしょうか。
筆者も実務で、大量データ更新のバッチ処理が想定の数倍以上の時間を要し、SQLチューニングやサーバ性能を疑ったものの改善しなかったことがあります。

最終的な原因は「INDEXの存在」でした。

SELECTでは高速化に貢献するINDEXですが、UPDATE処理では逆にパフォーマンス低下の原因になるケースがあります。本記事では、UPDATE処理が遅くなる本当の理由をデータベース内部の動作から解説します。


目次

UPDATE処理が遅くなる主な原因とは

UPDATEが遅くなる原因は複数ありますが、実務で最も見落とされやすいのがINDEX更新コストです。

代表的な原因を整理すると以下の通りです。

原因内容
INDEX更新処理更新時にINDEXも書き換えが発生
行ロック競合同時更新による待機
REDOログ増加更新量増大によるI/O負荷
テーブル断片化更新によるブロック分散
不要INDEX過多更新対象外でも更新対象になる

特に重要なのがINDEX更新処理です。

UPDATE性能の低下はINDEX数だけでなく、「INDEXが正しく利用されているか」も重要なポイントです。
SQLの書き方によってはINDEXが存在していても使用されず、想定外の性能劣化を引き起こす場合があります。

INDEXが効かない代表的な原因(LIKE検索・関数使用・暗黙的変換)については、以下の記事で詳しく解説しています。


UPDATE時にINDEXでは何が起きているのか

多くの人が誤解していますが、UPDATEは単純な「値の変更」ではありません。

データベース内部では以下の処理が実行されています。

  1. 対象行を検索
  2. データ行を書き換え
  3. INDEXエントリ削除
  4. INDEXエントリ再登録
  5. REDOログ記録

つまりUPDATEとは、

「DELETE + INSERT」に近い動作

をしています。

例えば以下のケースを考えます。

  • テーブルにINDEXが5個存在
  • UPDATE対象列がINDEX対象列

この場合、1行更新するたびに5個すべてのINDEX更新が発生します。

結果としてI/Oが急増し、処理時間が大幅に伸びます。


INDEXが多いほどUPDATEが遅くなる理由

INDEXはB-tree構造で管理されています。

UPDATE時には次の処理が発生します。

処理内容
古いキー削除INDEXツリーから削除
新しいキー追加再配置処理
ノード分割ページ分裂発生
ブロック書き込みディスクI/O増加

特に問題になるのがページ分割(Block Split)です。

INDEX領域に空きがない場合、新しいデータ配置のためにツリー構造の再編成が発生します。これが頻発するとUPDATE性能は急激に低下します。

SELECTとUPDATEのINDEX負荷比較

処理INDEX動作
SELECT読み取りのみ
UPDATE削除+追加
DELETEINDEX削除

UPDATE対象列がINDEXに含まれると遅くなる

以下は非常に重要なポイントです。

UPDATE対象INDEX影響
INDEX未使用列INDEX更新なし
INDEX列INDEX再構築発生
複合INDEX列全INDEX更新
主キー更新最大負荷

特に主キーや検索頻度の高い列をUPDATEすると、ほぼ確実に性能劣化が発生します。

実務では「ステータス列」にINDEXを付けた結果、更新バッチが極端に遅くなるケースがよくあります。


実行計画では問題が見えない理由

UPDATE遅延の厄介な点は、実行計画に原因が現れにくいことです。

実行計画は主に以下を示します。

  • 行取得方法
  • INDEX使用有無
  • JOIN方式

しかしINDEX更新コストは表示されません。

つまり、

SELECTは速い
実行計画も正常
それでもUPDATEだけ遅い

という現象が発生します。

これは設計問題でありSQL問題ではありません。


UPDATE性能を改善する具体的な対策

実務で効果が高い順に紹介します。

不要なINDEXを削除する

最も効果があります。

更新頻度が高いテーブルでは、

  • 検索用INDEX
  • 更新性能

のバランスが重要です。

使用されていないINDEXは削除候補です。


更新前にINDEXを一時削除する(大量更新)

大量UPDATEの場合は以下が有効です。

  1. INDEX削除
  2. UPDATE実行
  3. INDEX再作成

INDEX再作成はバルク処理となるため高速です。


UPDATEを分割実行する

一括更新はログ負荷を増大させます。

例:

  • 1万件単位でUPDATE
  • COMMITを分割

これだけで処理時間が改善する場合があります。


INDEX再構築を実施する

断片化が進んでいる場合は再構築が有効です。

代表例(Oracle):

断片化したINDEXはUPDATEコストを増大させます。


UPDATEとSELECTでINDEXの役割が逆になる理由

SELECTではINDEXは検索高速化のための存在です。

しかしUPDATEでは次のように役割が変わります。

処理INDEX効果
SELECT高速化
INSERTやや負荷増
UPDATE大きな負荷
DELETEINDEX削除負荷

つまりINDEXは「読む処理」には強く、「書く処理」には弱い構造です。

更新中心テーブルにINDEXを増やしすぎると、システム全体の性能低下につながります。


よくある質問(Q & A)

INDEXがある方がUPDATEも速くなりませんか?

なりません。検索は速くなりますが、更新時にはINDEX更新処理が追加されるため遅くなります。

INDEXが多いとどのくらい遅くなりますか?

INDEX数に比例して更新コストが増加します。実務では5〜10倍以上遅くなるケースもあります。

UPDATEが急に遅くなった原因は何ですか?

新規INDEX追加、データ増加、INDEX断片化が代表的な原因です。

UPDATE対象の列にINDEXが付いていなくても遅くなることはありますか?

はい、あります。UPDATE対象列自体にINDEXがなくても、その行を特定する検索条件にINDEXが使用されていない場合、全表走査(TABLE ACCESS FULL)が発生し処理時間が増加します。また、同一テーブルに多数のINDEXが存在する場合は、更新対象外のINDEXでも内部整合性維持のため処理負荷が発生することがあります。

UPDATEが遅い場合、まず確認すべきポイントは何ですか?

以下の順番で確認すると原因を特定しやすくなります。

確認項目チェック内容
INDEX数不要なINDEXが増えていないか
更新列INDEX対象列を更新していないか
実行計画TABLE ACCESS FULLになっていないか
更新件数一括大量更新になっていないか
INDEX断片化REBUILDが必要な状態でないか

特に「最近INDEXを追加していないか」は実務で非常に多い原因です。


まとめ

UPDATE処理が遅くなる原因の多くはSQLそのものではなくINDEX設計にあります。

INDEXは検索性能を向上させる重要な仕組みですが、更新処理では追加コストとして動作します。

特に更新頻度の高いテーブルでは、

  • INDEXを増やしすぎない
  • 更新列にINDEXを付与しない
  • 定期的にINDEX状態を確認する

といった設計が重要になります。

UPDATEが遅い場合は、まずINDEX数と更新対象列の関係を確認することが根本的な改善につながります。

よかったらシェアしてね!
  • URLをコピーしました!
0 0
Article Rating
申し込む
注目する
guest
0 コメント一覧
最も古い
最新 高評価
インラインフィードバック
すべてのコメントを見る
目次
0
あなたの考えが大好きです、コメントしてください。x