書き込みが遅い (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 が直接遅くなる。
根本原因: 重いトリガー / 制約
書き込みごとに起動するトリガーや、検証される制約 (特にインデックスのない外部キーのチェック) は、すべての行に追加のコストを加える。