📚

RDSのPerformance Insightsについて今更改めて

2024/12/13に公開

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_PerfInsights.html

しかしAWSのドキュメントってフレンドリーさが何かないんだよなあ、、読むと丁寧なのは別るんだけど、、なんでやろデザイン?

使えるエンジンサイズ

Amazon RDS DB エンジンとインスタンスクラスでサポートされている Performance Insights

にあるように、まとめると、small以下のインスタンスでは使えないということ。逆にmedium以上であれば使った方がよいという気がする。

料金

Performance Insights の料金とデータ保持によると

デフォルトでは、Performance Insights には、7 日間のパフォーマンスデータ履歴と 1 か月あたり 100 万件の API リクエストを含む無料利用枠が用意されています。

ということなんで小さなサービスであれば7日分のデーターがあればほとんど無料でいける。従ってmedium以上であれば使った方がよいと書いている。

では使ってみよう

有効化

こんな感じでonにする。

見てみる

まあこれはダミーデーターとおもってもらいたいんですけど、[+]のところで開閉できる。すると

このようなルーピーなクエリーを見る事ができる。これはまあN+1って奴すね。まあ、あとrowの数的にindex化されてないので二重苦みたいになってるんだろう。

ヘッダ行の解説(by ChatGPT)

  • wait によるロード (AAS)
  • SQL ステートメント
  • Calls/sec
  • Avg latency (ms)/call
  • Rows examined/call

とこれ以外にもヘッダはあるんだけど、とりあえずこれだけ。
ChatGPTによる解説

wait によるロード (AAS)

AASAverage Active Sessions)は、データベースにおける平均的なアクティブセッション数を示します。特に「wait によるロード」は、SQLクエリがCPU、I/O、ネットワーク、ロックなどでリソースを待機している状態の負荷を示します。

解釈:

  • 値が高いほど、SQLクエリがリソース待ち状態である可能性が高くなり、パフォーマンスボトルネックを引き起こしている可能性があります。
  • 各リソースの「待機イベント」ごとに分析することで、ボトルネックの原因を特定できます。

SQL ステートメント

実行されているSQLクエリの内容を示します。

解釈:

  • この項目を見ることで、どのクエリが問題を引き起こしているのか特定できます。
  • クエリ内容を確認し、インデックスの不足、冗長な条件、結合処理の非効率さなどを特定します。

Calls/sec

単位時間(1秒あたり)におけるSQLステートメントの呼び出し頻度(実行回数)を示します。

解釈:

  • 値が高いSQLは、頻繁に実行されているためシステムへの負荷が大きい可能性があります。
  • 頻繁に実行されるクエリは、特に効率化の対象になります(例: キャッシュの利用、インデックス追加など)。

Avg latency (ms)/call

SQLクエリ1回の実行にかかる平均時間をミリ秒単位で示します(平均レイテンシ)。

解釈:

  • レイテンシが長いほど、ユーザーやシステムに影響を与える可能性が高いです。
  • 平均実行時間が長いクエリは、クエリの再構築や最適化が必要な場合があります。
  • 長いレイテンシの原因には、以下が考えられます:
    • 非効率なクエリ設計(例: フルテーブルスキャン)
    • 適切なインデックスがない
    • 大量データの処理

Rows examined/call

SQLクエリ1回の実行で検査(読み取り)された行数を示します。

解釈:

  • 値が高いほど、データベースが無駄な行を読み取っている可能性があります(効率の低いクエリ)。
  • 行数が多い場合は、以下の原因をチェックします:
    • 適切なインデックスがない。
    • 条件が曖昧で、過剰な行を検索している。
    • テーブル結合が非効率である。

例えば

このようなQueryはExplainしてみたところノーインデックスで15000行が返却されていたんだけど、これに適切にインデックスを与えて効率化して様子を見る。このように割と少ない行数でここに出てるのは何となく N+1 っぽくなってるのが多そうだ。スローログで検知が難しいからなあ...

EXPLAIN SELECT COUNT(*) AS `cnt`  FROM `course_user` `CU`  WHERE `CU`.`course_id` = 123 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: CU
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 24634
     filtered: 10.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

こんなんとかも

ALTER TABLE `course_user` ADD INDEX idx_course_id (`course_id`);

なんかして

EXPLAIN SELECT COUNT(*) AS `cnt`  FROM `course_user` `CU`  WHERE `CU`.`course_id` = 123 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: CU
   partitions: NULL
         type: ref
possible_keys: idx_course_id
          key: idx_course_id
      key_len: 5
          ref: const
         rows: 1
     filtered: 100.00
        Extra: Using index
1 row in set, 1 warning (0.00 sec)

とかいう形でどんどん改善していく

良い所

スロークエリーログでは掴み辛いN+1が比較的検知しやすいように思う。まあ最終的にはこれはインデックスというよりはPGの方も何とかしないといけないんだろうとは思いますけどね。

Discussion