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

データベースが遅い

症状

アプリケーション全体が遅い。クエリに通常よりはるかに長い時間がかかり、ユーザーから苦情が出ている。

1. まず何が遅いのかを正確に明らかにする

すべてが遅いのか、特定のクエリ/画面なのか。いつ始まり、デプロイ/パッチ/データ増加と重なるか。システム全体か、単一の DB か。これにより調査対象を CPU、I/O、ロック、計画変更のいずれか 1 つの軸に絞り込む。

2. アクティブセッションと待機イベントを確認する

今何が実行され、何が待機しているか。支配的な待機イベント (I/O、ロック、ログ) がボトルネックを示す。

Oracle

SELECT sid, username, status, event, sql_id FROM v$session WHERE status='ACTIVE' AND type='USER';

PostgreSQL

SELECT pid, state, wait_event_type, wait_event, query FROM pg_stat_activity WHERE state='active';

MySQL

SELECT id, user, command, time, state, info FROM information_schema.processlist WHERE command<>'Sleep' ORDER BY time DESC;

SQL Server

SELECT session_id, status, wait_type, wait_time, blocking_session_id FROM sys.dm_exec_requests WHERE session_id IN (SELECT session_id FROM sys.dm_exec_sessions WHERE is_user_process = 1);

MongoDB

db.currentOp({ active: true, secs_running: { $gt: 1 } })

Redis

SLOWLOG GET 10

3. ブロッキングを確認する

遅延の最も一般的な原因は、1 つのセッションが他をブロックしていること。ブロッキングセッションを見つけ、チェーンの先頭を特定する。

Oracle

SELECT blocking_session, sid, seconds_in_wait, event FROM v$session WHERE blocking_session IS NOT NULL;

PostgreSQL

SELECT pid, pg_blocking_pids(pid) AS blocked_by, query FROM pg_stat_activity WHERE cardinality(pg_blocking_pids(pid))>0;

MySQL

SELECT * FROM sys.innodb_lock_waits\G

SQL Server

SELECT session_id, blocking_session_id, wait_type FROM sys.dm_exec_requests WHERE blocking_session_id<>0;

4. 最も高コストなクエリを抽出する

最もリソースを消費している上位 10 件のクエリを見つける。通常、問題の 90% は少数のクエリに起因する。

Oracle

SELECT sql_id, elapsed_time/1e6 sec, executions, sql_text FROM v$sql ORDER BY elapsed_time DESC FETCH FIRST 10 ROWS ONLY;

PostgreSQL

SELECT calls, total_exec_time, mean_exec_time, query FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10;

MySQL

SELECT digest_text, count_star, sum_timer_wait/1e12 sec FROM performance_schema.events_statements_summary_by_digest ORDER BY sum_timer_wait DESC LIMIT 10;

SQL Server

SELECT TOP 10 total_elapsed_time/execution_count avg_us, execution_count, SUBSTRING(t.text,1,200) FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t ORDER BY total_elapsed_time DESC;

5. 疑わしいクエリの計画を調べる

遅いクエリの EXPLAIN を取得する。全表スキャン、インデックスの欠如、不適切な結合順序、古い統計情報を探す。計画が突然変わった場合は、統計情報の収集を検討する。

Oracle

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('&sql_id', NULL, 'ALLSTATS LAST'));

PostgreSQL

EXPLAIN (ANALYZE, BUFFERS) <query>;

MySQL

EXPLAIN ANALYZE <query>;

SQL Server

SET STATISTICS PROFILE ON; <query>; SET STATISTICS PROFILE OFF;

MongoDB

db.my_collection.find({...}).explain('executionStats')  // COLLSCAN or IXSCAN?

6. システムリソースを確認する

OS レベルで CPU、I/O 待機 (iowait)、メモリ、ディスク使用量を確認する。キャッシュヒット率を確認し、低ければメモリのボトルネックの可能性がある。問題が DB の外にあることもある (ディスクフル、ノイジーネイバー VM)。

7. 判断: 応急処置か恒久対策か

即時の緩和: 暴走クエリを強制終了し、欠けているインデックスを追加し、統計情報を収集する。恒久対策: クエリ/インデックスを再設計し、メモリ設定を修正し、計画の安定性を確保する (ベースライン/ヒント)。

DBAtlas で開く →