giip
SES Proposal
Aurora MySQL性能インデックスパラメータログファイルAurora

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

そのまま実行できるコマンド

Check the current slow query log and performance_schema settings参照のみ
対象
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.

Check currently running sessions参照のみ
対象
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.

Check long-running open transactions (works even when performance_schema is disabled)参照のみ
対象
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.

Aggregate executed SQL by digest (when performance_schema is ON)参照のみ
対象
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.

Check the execution plan (EXPLAIN / EXPLAIN ANALYZE)
対象
`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.

Enable the slow query log and export it to CloudWatch Logs
対象
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 table

The 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.

Enable performance_schema (requires an instance restart)
対象
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_NAMESchema the digest belongs toNarrow down to the target application's schema
digest_headBeginning of the SQL statement with literals normalizedSQL statements of the same shape are grouped together. Refer to `DIGEST_TEXT` directly for the full text
exec_countNumber of executions (`COUNT_STAR`)Distinguish whether a single execution is slow, or the total is large due to a high execution count
total_secCumulative execution time (seconds)The top entries are the main cause of load. Check this first
avg_secAverage execution time per call (seconds)A query with a small total but large average can become a problem depending on when it runs
rows_examinedCumulative number of rows scannedIf this is orders of magnitude larger than `rows_sent`, the index is likely not being used effectively
rows_sentCumulative number of rows returnedThe ratio to `rows_examined` is a measure of efficiency
no_index_usedNumber of executions that did not use an indexIf nonzero, check the access method with `EXPLAIN`
tmp_disk_tablesNumber of times a temporary table was created on diskIf large, it's a candidate for reviewing sorting/grouping logic
FIRST_SEEN / LAST_SEENTime first/last observedCheck 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

考えられる原因(可能性の高い順)

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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. 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. 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. 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. 4

    Check long-running transactions and locks

    参照のみ

    Refer to `information_schema.INNODB_TRX`. This can be run even when `performance_schema` is disabled.

  5. 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. 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.

バージョン・環境による違い

Aurora MySQL 2.x (MySQL 5.7-compatible)`EXPLAIN ANALYZE` is not available. To see execution plan details, use `EXPLAIN FORMAT=JSON`.
Aurora MySQL 3.x (MySQL 8.0-compatible)`EXPLAIN ANALYZE` and `performance_schema.processlist` are available. Since some MySQL 8.0-series versions deprecate `information_schema.PROCESSLIST`, consider migrating to `performance_schema.processlist` in the long term.
Performance InsightsEnabling it is an instance-level setting. Check AWS's pricing/spec pages for the latest retention period and supported instance class conditions (this article does not state them definitively).

これで解決しない場合に確認すること

  • 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エージェントと人間の専門家が継続的に監視・運用しています。

関連するナレッジ

関連サービス

Request an investigation into the slow query's cause

同じ確認を複数の環境で継続する必要がある場合は、運用体制ごと相談できます。

Request an investigation into the slow query's cause

ナレッジベース一覧へ