AWS Redshiftのクエリ速度改善してみた話

## 背景
先日機会があって、awsのRedshift Query Tuning Workshopに参加させていただいたのでそのとき学んだことを活かして業務で扱うRedshiftのクエリをチューニングしてみました。この記事はその備忘録です。
（その時の資料は一般公開されているそうなので、下記の参考欄に添付しておきます）

## 初めに
今回のワークショップで口酸っぱく言われたことは
1. 分析は時間ベースで行うこと
1. システマチックにボトルネックを特定し、チューニングを行うこと

の二つです、その他にもたくさん勉強になることはありましたが誰にでも当てはまることはこの二つだと思います。
この2点を念頭において実際にどのような操作を行なったか書いていきます。

## ボトルネックの特定
初めに確認するべきはクエリにおいて時間のかかっているところはどの部分か確認することです。

まず、以下のコードを実行して該当のクエリの全体にかかっている時間を把握します（[詳しくはこちら](https://docs.aws.amazon.com/redshift/latest/dg/SYS_QUERY_HISTORY.html) ）
```
SELECT *
    FROM sys_query_history
    WHERE query_id = **調査対象のクエリID**
```
出力されたものを一部抜粋するとこんな感じ![スクリーンショット 2025-03-08 20.57.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/bbc03848-8fa0-4b79-b69c-833ef29251ab.png)


execution_timeを見ると23ミリ秒くらいかかってそうですね！
十分早くね？とも思いますが改善できるところはしていきたいですからね！

次に、各セグメントごとの実行時間を確認します([詳しくはこちら](https://docs.aws.amazon.com/redshift/latest/dg/SYS_QUERY_DETAIL.html))
```
SELECT
   query_id
   , child_query_sequence
   , stream_id
   , segment_id
   , step_id
   , step_name
   , table_id
   , coalesce(table_name,'')|| coalesce(source,'') as table_name
   , start_time
   , end_time
   , duration
   , input_bytes
   , output_bytes
   , input_rows
   , output_rows
   , blocks_read
   , local_read_io
   , remote_read_io
   , is_rrscan
   , data_skewness
   , time_skewness
   , spilled_block_local_disk
   , spilled_block_remote_disk
  FROM
   sys_query_detail
  WHERE query_id = **調査対象のクエリID**
  ORDER BY
   query_id
   , child_query_sequence
   , stream_id
   , segment_id
   , step_id;
```
これで出力されたものはこんな感じ![スクリーンショット 2025-03-08 21.01.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/5fe4d14b-fd15-49ac-a5bc-2d5b3cf2fb53.png)
inputされてる数とoutputされてる数が違ったり、data_skewnessからデータの不均衡かありそうなのがわかります

ここまででどこにどれだけ時間がかかっているのかが把握できました

## 原因特定
原因特定はそれぞれのケースによって異なるので、自分が行ったことを書いていきます。
まずは調査対象のクエリを先頭に
```
EXPLAIN
```
を追加して、実行計画を確認します。([詳しくはこちら](https://docs.aws.amazon.com/redshift/latest/dg/r_EXPLAIN.html))
idとかは見せることができないので微妙な感じですがこんな感じ![スクリーンショット 2025-03-08 21.14.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/18c75f47-a458-4f77-8163-54bd41a61835.png)

これまでの結果からデータに不均衡がありそうだと判断したため、データの分散とソートキーの効果の確認します([詳しくはこちら](https://docs.aws.amazon.com/redshift/latest/dg/r_SVV_TABLE_INFO.html))
```
SELECT "table", diststyle, sortkey1, skew_rows, unsorted
    FROM svv_table_info WHERE "table" = **調査対象のテーブル名**
```
結果はこんな感じ
![スクリーンショット 2025-03-08 22.04.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/c2643f8b-9696-4f2e-8b31-8247ee41d7ba.png)
skew_rowsは1に近いほど分散が小さく、100はかなり分散が大きいです。
unsortedはsortkeyでのソートがうまく行えていない割合なのでこの二つを改善すれば速度は速くなるはずです

## 改善
ここまでの調査で改善方針が定まったので実際に改善していきましょう！
まずは再ソートを行なってunsortedをなくしたいと思います。
```
VACUUM FULL **再ソートしたいテーブル名**
```
そうすると
![スクリーンショット 2025-03-08 22.24.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/138fa53d-d8ec-4fba-a15d-1fb0bdd2e4e5.png)
こうなります。
ちゃんと再ソートできてそうですね！
あとはskew_rowsを小さくするために分散キーを見直します。
```
ALTER TABLE **分散キーを変更したいテーブル名** ALTER DISTKEY **新しい分散キー**;
```
クエリの中身を見せることができないので結果論になってしまいますがこうなりました！
![スクリーンショット 2025-03-08 22.39.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/dc044e29-93c1-4ce2-980e-cac8edbdaf24.png)
変化なし！なんでや！？いろいろ試してみましたが今回はうまく分散キーを設定することはできませんでした…うまくできたら追記します。

## 結果
ではお待ちかねの結果です
再度クエリを実行して
```
SELECT *
    FROM sys_query_history
    WHERE query_id = **調査対象のクエリID**
```
時間を見てみると・・・
![スクリーンショット 2025-03-08 23.53.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820752/c615940f-b638-41f9-98ca-2c7be52a43db.png)
大体14ミリ秒くらいになりました！
元々23ミリ秒ほどかかっていたので、約10ミリ秒早くなりましたね、ほぼ半分です！

## 感想
今回はRedshiftのクエリの速度改善の一連の流れをやってみました！
色々雑になってしまった部分もありますが楽しかったです。
今回プロセスの理解のために実際にクエリエディタ上で作業をしましたが、実はボトルネックの特定まではmazon Redshift管理コンソールからGUIで確認できます… ていうか多分そっちの方がわかりやすいので、もしこの記事を見て試してみようって思う方がいたら、GUIでの確認をしてみてください。

## 参考
https://catalog.us-east-1.prod.workshops.aws/workshops/3a8b525f-161f-4e14-a166-4e0040913258/ja-JP