DBAtlas · データベース運用アトラス

書き込みが遅い (INSERT/UPDATE のレイテンシ)

INSERT/UPDATE/DELETE の操作が想定より遅い。まず書き込みが何を待っているか (commit/redo、ロック、ディスク、行ごとのオーバーヘッド) を特定し、段階的に根本原因まで掘り下げる。

書き込みは何を待っているか?

待機イベントを見てボトルネックを分類する: 支配的なのは commit/redo (WAL) の同期か、ロックか、ディスクの書き込みレイテンシか、それとも行ごとのインデックス/トリガーのオーバーヘッドか?

SELECT event, total_waits, ROUND(time_waited/100,1) AS sec_waited
FROM v$system_event
WHERE event IN ('log file sync','log file parallel write','enq: TX - row lock contention','db file sequential read')
ORDER BY time_waited DESC;
  • commit / redo (WAL 同期) を待機している
  • ロックを待機している
  • 行ごとのオーバーヘッド (インデックス/トリガー) が疑われる
  • ディスクの書き込みレイテンシが高い

コミットのパターンか、fsync か?

行ごとに個別にコミットする (autocommit) と、行数と同じ回数だけ redo/ログの同期が発生する。逆に、コミット回数は妥当でも各コミットが fsync を待っている場合、問題はログディスクのレイテンシ。

SELECT name, value FROM v$sysstat WHERE name IN ('user commits','redo writes','redo size');
SELECT ROUND(time_waited_micro/GREATEST(total_waits,1)/1000,2) AS ms_per_sync FROM v$system_event WHERE event='log file sync';
  • autocommit / 行ごとのコミット
  • コミットがログの同期 (fsync) を待機している

誰がロックを保持しているか?

書き込みがロックを待機している場合: 別のセッションが同じ行/インデックスを保持しているか、多数のセッションが同じ「ホットな」行に書き込もうとしている可能性がある。

SELECT s.sid, s.serial#, s.username, s.blocking_session, s.event, s.seconds_in_wait
FROM v$session s WHERE s.blocking_session IS NOT NULL;
  • 別のセッションがロックを保持している
  • 多数のセッションが同じホットな行に書き込んでいる

行ごとのオーバーヘッドはどこから来ているか?

すべての INSERT/UPDATE は、テーブル上のすべてのインデックスも更新し、トリガー/制約があれば起動する。インデックスが多すぎたり、重いトリガーがあったりすると、書き込みが大幅に遅くなる。

SELECT index_name, uniqueness FROM user_indexes WHERE table_name='T';
SELECT trigger_name, triggering_event FROM user_triggers WHERE table_name='T';
  • テーブルのインデックスが多すぎる / 不要なインデックスがある
  • 重いトリガーまたは制約のコストがある

根本原因: autocommit / 行ごとのコミット

行ごとに個別にコミットすると、行数と同じ回数だけ redo/ログの同期が繰り返される。操作をまとめることで、コミット (つまり fsync) の回数を劇的に減らせる。

根本原因: 低速な redo/ログディスク (fsync のレイテンシ)

すべてのコミットは、redo/WAL レコードが永続ストレージに書き込まれる (fsync) まで待機する。ログディスクが低速 (書き込みレイテンシが高い、IOPS が不足) だと、すべてのコミットがそのレイテンシを負う。

根本原因: 別のセッションがロックを保持している

書き込みが、別のセッションが保持する行/インデックスのロックを待機している。ブロッカーは通常、長時間実行中のトランザクションか、コミットし忘れたトランザクション。

根本原因: ホットな行の競合

多数のセッションが同じ行 (例: カウンタ、シーケンス番号、残高) に書き込もうとしている。全セッションが同じロックを待つキューに並び、書き込みが直列化される。

根本原因: 過剰なインデックスのオーバーヘッド

テーブル上のすべてのインデックスは書き込みのたびに更新される。インデックスが多い、または未使用のインデックスがあると、INSERT/UPDATE が直接遅くなる。

根本原因: 重いトリガー / 制約

書き込みごとに起動するトリガーや、検証される制約 (特にインデックスのない外部キーのチェック) は、すべての行に追加のコストを加える。

DBAtlas で開く →