How to Investigate a Slow Query in Aurora MySQL
公開日 2026-08-13 · 更新日 2026-08-13 · 最終検証日 2026-08-13
結論
When a specific query is slow in Aurora MySQL, isolate the cause in this order: (1) identify the slow SQL using the slow query log (`slow_query_log` and `long_query_time`), (2) check running sessions and wait states with `SHOW FULL PROCESSLIST`, and (3) check the execution plan with `EXPLAIN`. If `performance_schema` is enabled, digest aggregation and Performance Insights let you trace wait events as well, but even when it is disabled, these three steps plus CloudWatch metrics can isolate most causes.
この文書の適用条件
| 対象製品 | Aurora MySQL (MySQL-compatible edition) |
|---|---|
| 確認バージョン | Aurora MySQL 2.x (MySQL 5.7-compatible) / 3.x (MySQL 8.0-compatible). `EXPLAIN ANALYZE` was added in MySQL 8.0, so it is available only on 3.x |
| 適用環境 | Amazon Aurora (AWS) |
| 必要権限 | Read-only operations require `SELECT` on the target schema. Viewing other users' sessions or transactions requires the `PROCESS` privilege. Changing parameters requires IAM `rds:ModifyDBParameterGroup` and master-user-equivalent privileges |
| 実行影響 | No impact for read-only operations. `EXPLAIN ANALYZE` actually executes the target query. Parameter changes constitute a configuration change |
| 再起動 | Not required for read-only operations. Enabling `performance_schema` requires an instance restart |
| 最終検証日 | 2026-08-13 |
そのまま実行できるコマンド
- 対象
- Aurora MySQL 2.x / 3.x
- 権限
- Connection privilege (read global variables)
- 変更作業
- None (read-only)
- Production実行
- Possible
-- 対象: Aurora MySQL 2.x / 3.x
-- 権限: 接続権限(グローバル変数の参照のみ)
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SHOW GLOBAL VARIABLES WHERE Variable_name IN (
'slow_query_log',
'long_query_time',
'log_output',
'log_queries_not_using_indexes',
'min_examined_row_limit',
'performance_schema'
);If `performance_schema` is `OFF`, the digest aggregation described in this article cannot be used. In that case, isolate the cause using the slow query log, PROCESSLIST, `information_schema.INNODB_TRX`, and CloudWatch metrics.
- 対象
- Aurora MySQL 2.x / 3.x
- 権限
- Viewing sessions other than your own requires the `PROCESS` privilege
- 変更作業
- None (read-only)
- Production実行
- Possible
-- 対象: Aurora MySQL 2.x / 3.x
-- 権限: 自分以外のセッションを見るには PROCESS 権限
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT
ID,
USER,
HOST,
DB,
COMMAND,
TIME AS elapsed_sec,
STATE,
LEFT(INFO, 200) AS query_head
FROM information_schema.PROCESSLIST
WHERE COMMAND <> 'Sleep'
ORDER BY TIME DESC;This provides the same information as `SHOW FULL PROCESSLIST` in a form that can be sorted and filtered. On MySQL 8.0-compatible Aurora MySQL 3.x, `performance_schema.processlist` is also available; since its implementation doesn't take a global mutex, it has less impact in environments with many connections.
- 対象
- Aurora MySQL 2.x / 3.x
- 権限
- `PROCESS` privilege
- 変更作業
- None (read-only)
- Production実行
- Possible
-- 対象: Aurora MySQL 2.x / 3.x
-- 権限: PROCESS 権限
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT
trx_id,
trx_state,
trx_started,
TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS open_sec,
trx_mysql_thread_id,
trx_rows_locked,
trx_rows_modified,
LEFT(trx_query, 200) AS current_query
FROM information_schema.INNODB_TRX
ORDER BY trx_started ASC;If the slowness is caused by lock waiting rather than a specific query, you'll see transactions here that have remained `RUNNING` for a long time. This can be queried regardless of whether `performance_schema` is enabled.
- 対象
- Aurora MySQL 2.x / 3.x (assumes `performance_schema = ON`)
- 権限
- `SELECT` on `performance_schema`
- 変更作業
- None (read-only)
- Production実行
- Possible
-- 対象: Aurora MySQL 2.x / 3.x(performance_schema = ON が前提)
-- 権限: performance_schema への SELECT
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT
SCHEMA_NAME,
LEFT(DIGEST_TEXT, 200) AS digest_head,
COUNT_STAR AS exec_count,
ROUND(SUM_TIMER_WAIT / 1000000000000, 3) AS total_sec,
ROUND(AVG_TIMER_WAIT / 1000000000000, 6) AS avg_sec,
SUM_ROWS_EXAMINED AS rows_examined,
SUM_ROWS_SENT AS rows_sent,
SUM_NO_INDEX_USED AS no_index_used,
SUM_CREATED_TMP_DISK_TABLES AS tmp_disk_tables,
FIRST_SEEN,
LAST_SEEN
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 20;The unit of `*_TIMER_WAIT` is picoseconds, so it is divided by 10^12 to convert to seconds. The aggregation is cumulative since instance startup and is reset on restart or failover.
- 対象
- `EXPLAIN` works on 2.x / 3.x; `EXPLAIN ANALYZE` only on 3.x (MySQL 8.0-compatible)
- 権限
- `SELECT` on the target table
- 変更作業
- None. However, `EXPLAIN ANALYZE` actually executes the target query
- Production実行
- `EXPLAIN` is possible. `EXPLAIN ANALYZE` only when the execution load is acceptable
-- 対象: EXPLAIN は Aurora MySQL 2.x / 3.x、EXPLAIN ANALYZE は 3.x(MySQL 8.0互換)のみ
-- 権限: 対象テーブルへの SELECT
-- 変更作業: なし(EXPLAIN ANALYZE はクエリを実際に実行する点に注意)
-- Production 実行: EXPLAIN は可能/EXPLAIN ANALYZE は実行負荷を許容できる場合のみ
-- 1) 実行計画だけを見る(クエリは実行されない)
EXPLAIN
SELECT id, name, updated_at
FROM SampleDB.sample_table
WHERE status = 'active'
AND updated_at >= '2026-08-01'
ORDER BY updated_at DESC
LIMIT 100;
-- 2) 実測値つきの実行計画(Aurora MySQL 3.x のみ。クエリを実際に実行する)
EXPLAIN ANALYZE
SELECT id, name, updated_at
FROM SampleDB.sample_table
WHERE status = 'active'
AND updated_at >= '2026-08-01'
ORDER BY updated_at DESC
LIMIT 100;`EXPLAIN ANALYZE` returns actual measured row counts and timing instead of estimates, so you can directly see the gap between estimate and reality. However, since it actually executes the query, do not use it for write queries or heavy aggregations. `EXPLAIN FORMAT=JSON` returns details including cost values without actually executing the query.
- 対象
- Aurora MySQL 2.x / 3.x (DB parameter group and DB cluster settings)
- 権限
- IAM: `rds:ModifyDBParameterGroup`, `rds:ModifyDBCluster`
- 変更作業
- Yes (parameter change and log output setting change)
- Production実行
- Carry out only after going through change management. Expect an increase in log volume
# 対象: Aurora MySQL 2.x / 3.x(DBパラメータグループとDBクラスター設定)
# 権限: IAM rds:ModifyDBParameterGroup, rds:ModifyDBCluster
# 変更作業: あり(パラメータ変更 + ログ出力先の変更)
# Production 実行: 変更管理を通したうえで実施。ログ量とストレージ増加を見込むこと
# 1) スロークエリログを有効化する(いずれも動的パラメータとして扱われる想定。
# 実際の反映方法は describe-db-parameters の ApplyType で確認すること)
aws rds modify-db-parameter-group \
--db-parameter-group-name example-aurora-mysql-params \
--parameters '[
{"ParameterName":"slow_query_log","ParameterValue":"1","ApplyMethod":"immediate"},
{"ParameterName":"long_query_time","ParameterValue":"1","ApplyMethod":"immediate"},
{"ParameterName":"log_output","ParameterValue":"FILE","ApplyMethod":"immediate"}
]'
# 2) クラスター単位でスロークエリログをCloudWatch Logsへ出力する
aws rds modify-db-cluster \
--db-cluster-identifier example-aurora-cluster \
--cloudwatch-logs-export-configuration '{"EnableLogTypes":["slowquery","error"]}' \
--apply-immediately
# 3) 反映後の値を確認する
aws rds describe-db-parameters \
--db-parameter-group-name example-aurora-mysql-params \
--query "Parameters[?ParameterName=='slow_query_log' || ParameterName=='long_query_time'].{Name:ParameterName,Value:ParameterValue,Apply:ApplyType,Status:ApplyMethod}" \
--output tableThe smaller `long_query_time` is set, the more queries get logged, increasing log volume and CloudWatch Logs cost. Start at around 1 second and lower it as needed. Setting `log_output` to `TABLE` lets you query the `mysql.slow_log` table with SQL, but since writes become table inserts, the nature of the load changes.
- 対象
- Aurora MySQL 2.x / 3.x (DB parameter group)
- 権限
- IAM: `rds:ModifyDBParameterGroup`, `rds:RebootDBInstance`
- 変更作業
- Yes (static parameter change + instance restart)
- Production実行
- Not possible due to the restart involved. Plan execution during a maintenance window
# 対象: Aurora MySQL 2.x / 3.x(DBパラメータグループ)
# 権限: IAM rds:ModifyDBParameterGroup, rds:RebootDBInstance
# 変更作業: あり(静的パラメータ変更 + インスタンス再起動)
# Production 実行: 不可(再起動を伴うためメンテナンス時間帯に計画実行)
# 1) performance_schema を有効化する(再起動時に反映)
aws rds modify-db-parameter-group \
--db-parameter-group-name example-aurora-mysql-params \
--parameters '[
{"ParameterName":"performance_schema","ParameterValue":"1","ApplyMethod":"pending-reboot"}
]'
# 2) 反映のためインスタンスを再起動する(接続断が発生する)
aws rds reboot-db-instance --db-instance-identifier example-aurora-instance`performance_schema` is a parameter that requires a restart. Because the restart causes a connection drop with an impact equivalent to a failover, always treat it as a planned outage. Some detailed information in Performance Insights also depends on `performance_schema`. The increase in memory usage from enabling it varies by environment, so measure it in a test environment beforehand.
結果の読み方
| 列 | 意味 | 確認するポイント |
|---|---|---|
| SCHEMA_NAME | Schema the digest belongs to | Narrow down to the target application's schema |
| digest_head | Beginning of the SQL statement with literals normalized | SQL statements of the same shape are grouped together. Refer to `DIGEST_TEXT` directly for the full text |
| exec_count | Number of executions (`COUNT_STAR`) | Distinguish whether a single execution is slow, or the total is large due to a high execution count |
| total_sec | Cumulative execution time (seconds) | The top entries are the main cause of load. Check this first |
| avg_sec | Average execution time per call (seconds) | A query with a small total but large average can become a problem depending on when it runs |
| rows_examined | Cumulative number of rows scanned | If this is orders of magnitude larger than `rows_sent`, the index is likely not being used effectively |
| rows_sent | Cumulative number of rows returned | The ratio to `rows_examined` is a measure of efficiency |
| no_index_used | Number of executions that did not use an index | If nonzero, check the access method with `EXPLAIN` |
| tmp_disk_tables | Number of times a temporary table was created on disk | If large, it's a candidate for reviewing sorting/grouping logic |
| FIRST_SEEN / LAST_SEEN | Time first/last observed | Check whether this matches when slowness began |
こういう状況で使います
- The same query that was fine until yesterday suddenly became slow at some point
- Timeouts have increased on the application side, but CPU usage is not high
- Only a specific screen or batch job is slow; other processing is normal
- Tried to check Performance Insights, but details don't appear because `performance_schema` is disabled
- The same query remains in `SHOW PROCESSLIST` for a long time
考えられる原因(可能性の高い順)
01
The execution plan changed and the index is no longer being used
An increase in data volume or a statistics update can cause the optimizer to choose a different access method. If `rows_examined` is extremely large compared to `rows_sent`, this is likely the cause.
02
Execution is stalled due to lock waiting
Even if the query itself is lightweight, it will wait if another transaction holds a row lock. Check whether `information_schema.INNODB_TRX` shows a transaction that has remained open for a long time.
03
Scan cost increased due to growing data volume
Even with the same execution plan, processing time increases as the number of target rows grows. In this case, the index design or search conditions need to be reviewed; parameter tuning alone will not resolve it.
04
Sort operations or temporary tables are spilling to disk
When the target of `ORDER BY` or `GROUP BY` is large, a temporary table is created on disk. This can be checked via `SUM_CREATED_TMP_DISK_TABLES` in the digest aggregation.
05
Replica lag or resource contention on the reader instance side
If reads are directed to the reader endpoint, the load situation differs between the writer and reader. First isolate which instance is slow.
確認手順
- 1
Identify which instance and time window
参照のみCheck CloudWatch's `CPUUtilization`, `DatabaseConnections`, `ReadLatency` / `WriteLatency`, and `Deadlocks` to narrow down the time window and instance where the event occurred.
- 2
Check the slow query log settings
参照のみRun the `SHOW GLOBAL VARIABLES` command above to check whether logging is actually happening and whether `long_query_time` matches the real situation.
- 3
Check running sessions
参照のみUse `information_schema.PROCESSLIST` to check whether the slow query is actually running or waiting. The `STATE` column is a clue.
- 4
Check long-running transactions and locks
参照のみRefer to `information_schema.INNODB_TRX`. This can be run even when `performance_schema` is disabled.
- 5
Identify top offenders via digest aggregation
参照のみIf `performance_schema` is enabled, check `events_statements_summary_by_digest` sorted by cumulative execution time in descending order.
- 6
Check the execution plan of the target SQL
低Use `EXPLAIN` to check the access method, index used, and estimated row count. Only use `EXPLAIN ANALYZE` (Aurora MySQL 3.x) when you want to see the gap between estimate and actual, and only within a load the system can tolerate.
対応方法
すぐに実施できる低リスクの対応
Enable the slow query log to pin down the target SQL
高Before acting on guesswork, confirm the actually slow SQL via the log. Start `long_query_time` at around 1 second.
Terminate the lock-holding session from the application side
高If a long-open transaction is the cause, first stop the processing on the application side. `KILL` on the DB side is a last resort, and it rolls back the in-progress update.
事前検討が必要な変更
Add an index matching the search conditions
高Based on the `EXPLAIN` result, consider a composite index that satisfies both filtering and sorting. Since adding an index is a schema change, it requires verification in a test environment and scheduling for an appropriate time window.
Rewrite the query to reduce the number of rows scanned
中Reduce `rows_examined` through changes such as not applying functions to condition columns, returning only necessary columns, and reviewing the paging approach.
Export the slow query log to CloudWatch Logs for ongoing monitoring
高Instead of viewing logs only temporarily, aggregate them so trends can be tracked over time. Costs accrue in proportion to log volume.
再起動・サービス影響を伴う変更
Enable performance_schema
高This is a static parameter that requires a restart. Since it causes a connection drop, treat it as a planned outage. After enabling it, digest aggregation and detailed Performance Insights information become available.
Change the instance class
高This is an option when CPU or memory is chronically insufficient, but it does not solve execution-plan problems for a single query. Finish isolating the cause first before deciding.
!注意事項
- `EXPLAIN ANALYZE` actually executes the target query. Do not use it for write queries or heavy aggregations.
- Enabling `performance_schema` involves an instance restart. Since it causes a connection drop, it cannot be done without downtime.
- Setting `long_query_time` extremely low makes the log output itself a source of load and storage consumption.
- `KILL` triggers a rollback of the in-progress transaction, and the rollback can take as long as or longer than the original processing. Do not use it lightly.
- The digest aggregation is a cumulative value since instance startup. Immediately after a failover or restart, the sample size is too small to be a useful basis for judgment.
- This article describes a procedure for isolating the cause; it does not guarantee that applying any specific setting will make things faster.
バージョン・環境による違い
これで解決しない場合に確認すること
Check application-side timeout and connection pool settings
If things look slow even though the DB-side execution time hasn't changed, connection waiting or pool exhaustion can be the cause.
Isolate whether the slowness is on the writer or reader side
Run the same SQL on the writer and reader separately to see if there's a difference. If there is, suspect an instance-specific load factor.
Check CloudWatch's `ReadIOPS` / `WriteIOPS` and buffer pool hit ratio
The approach differs depending on whether the wait is on the storage side or the CPU side.
Cross-reference schema changes or deployment history with the timing
Check whether an index was dropped or an application query was changed around the time things slowed down.
Check whether the same symptom appears across multiple queries
The direction of investigation differs depending on whether it's a single-query problem or an instance-wide problem.
この文書の根拠と限界
製品の公式ドキュメントに基づく説明
This is a general verification procedure based on MySQL's slow-query-log-related system variables, the public specifications of `information_schema.PROCESSLIST` / `INNODB_TRX`, `performance_schema.events_statements_summary_by_digest`, and `EXPLAIN` / `EXPLAIN ANALYZE`, as well as the public specifications of Amazon RDS / Aurora parameter groups and log output. It does not include measured values from any specific environment.
よくある質問
Can this be run in production?
`SHOW GLOBAL VARIABLES`, `information_schema.PROCESSLIST`, `information_schema.INNODB_TRX`, the digest aggregation, and `EXPLAIN` are all read-only and can be run as-is in production. `EXPLAIN ANALYZE` actually executes the query, and parameter changes constitute a configuration change, so check the impact of each before carrying them out.
Can the cause be investigated even if performance_schema is disabled?
Yes. You can identify the slow SQL via the slow query log, check the running state and locks with `SHOW FULL PROCESSLIST` and `information_schema.INNODB_TRX`, and view the execution plan with `EXPLAIN` — this flow can isolate most causes. Since enabling it requires a restart, first exhaust what you can do while it stays disabled.
Is a restart required to enable performance_schema?
Yes. Change `performance_schema` to 1 in the DB parameter group and restart the target instance to apply it. Since the restart causes a connection drop, treat it as a planned outage.
What permissions are required?
If you only need `EXPLAIN` on your own session and the target table, `SELECT` on the target schema is enough. Viewing other users' sessions or `INNODB_TRX` requires the `PROCESS` privilege. Parameter changes require IAM privileges (such as `rds:ModifyDBParameterGroup`).
How should the results be interpreted?
If `rows_examined` is orders of magnitude larger than `rows_sent`, it's an access-method problem; if `INNODB_TRX` shows a long-running transaction, it's lock waiting; if neither applies and CPU or I/O is pegged, it's a resource issue. Sort the digest aggregation by "cumulative execution time" and distinguish single-call slowness from high call count.
Is it okay to use EXPLAIN ANALYZE in production?
Use it only after confirming the target is read-only and the load is acceptable to run. In exchange for returning actual measurements instead of estimates, `EXPLAIN ANALYZE` runs the query to completion. If you're unsure, use `EXPLAIN FORMAT=JSON` instead.
この文書がカバーする質問
- Want to enable and check the slow query log in Aurora MySQL
- How to proceed with performance analysis in an environment where performance_schema=OFF
- Want to check running queries and wait states in MySQL
- Want to judge from EXPLAIN results whether the index is not being used effectively
リスク表示の意味
- 参照のみデータと設定を変更しません。
- 低影響は限定的ですが、権限と負荷の確認が必要です。
- 中性能・ロック・コストに影響する可能性があります。
- 高障害・データ損失・復旧作業が発生する可能性があります。
- 専門家レビュー必須本番適用前に別途レビューが必須です。
GIIPの対応範囲
The procedure in this article can get you as far as identifying a single slow query. What's difficult in actual operations is that information from "the moment" it became slow often isn't preserved. GIIP continuously collects the slow query log and CloudWatch metrics, and also records the running sessions and transaction state at the moment a threshold is exceeded, so that an investigation can begin afterward without waiting to reproduce the issue. Day-to-day collection and initial triage are handled by an AI agent, and a human takes over at the stage where judgment is required, such as changing an execution plan or adding an index.
執筆・技術検証
GIIP プロダクション運用チーム
大規模Webサービス、SQL Server、Oracle、AWS、Azureの設計・移行・運用に約30年従事。x12largeクラスのAWS RDS for SQL Server環境12セット、約12万テーブルのOracle環境、約3TBのTiDBからAurora MySQLへの移行を経験。現在も複数のクラウドデータベースと約30のWebサービスを、AIエージェントと人間の専門家が継続的に監視・運用しています。
How to Collect and Review Audit Logs in Aurora MySQL
A procedure for enabling Aurora MySQL's Advanced Auditing via a cluster parameter and reviewing it through CloudWatch Logs or RDS log files. Also organizes how to narrow down what gets recorded.
aurora-mysqlWhat to Check When Migrating from utf8mb3 to utf8mb4 in Aurora MySQL
The first thing that breaks when converting to utf8mb4 is index key length. This organizes the SQL for finding targets, how to choose a collation, the impact of conversion, and where the settings live.
sql-serverSQL to Check Statistics Last-Updated Time per Table in SQL Server
A read-only SQL script using sys.stats and STATS_DATE that lists the last-updated time and the number of rows modified since the last update, per table and statistic.
monitoringWhat to Configure When Monitoring Servers and Databases 24/7
A checklist, organized by layer, of what to monitor, how to think about thresholds, the escalation structure, and why synthetic monitoring is necessary when designing 24/7 monitoring.
関連サービス
Request an investigation into the slow query's cause
同じ確認を複数の環境で継続する必要がある場合は、運用体制ごと相談できます。
Request an investigation into the slow query's cause