Athena Query Result Reuseを試してみた

# 背景・目的
11/8に[Amazon Athena announces Query Result Reuse to accelerate queries](https://aws.amazon.com/about-aws/whats-new/2022/11/amazon-athena-query-result-reuse-accelerate-queries/)が発表されましたので、試してみました。

# まとめ
- Athena Engine 3 が必要
- 最大7日間再利用可能(デフォルト60分)。以下の単位で指定可能。
    - 分
    - 時間
    - 日にち
- 同じ結果であれば、ミリSecで結果が返される。

# 概要
## Reusing query resultsとは？
Athenaでクエリを再実行する場合、オプションで、最後に保存されたクエリ結果を再利用することを選択が可能。
これにより、パフォーマンスが向上し、スキャンされるバイト数に関してコストが削減される。
特定の時間枠内で結果が変化しないことがわかっている場合に役立つ。

クエリ結果を再利用する最大期間を指定でき、指定した期間より古くない限り、保存された結果が使用される。
クエリ結果を再利用できる最大期間は、分、時間、または日で指定可能。指定可能な最大期間は、使用する時間単位に関係なく7日。デフォルトは 60 分。

## 挙動
クエリの結果の再利用を有効にすると、Athena は同じワークグループ内で以前に実行されたクエリを探し、対応する保存されたクエリ結果を見つけた場合、クエリを再実行せずに、以前の結果の場所を指すか、そこからデータを取得する。

結果の再利用オプションを有効にするクエリの場合、Athena は、次の条件がすべて当てはまる場合にのみ、ワークグループ フォルダーに保存された最後のクエリ結果を再利用する。

- クエリ文字列は完全一致
- データベースとカタログ名が一致します。
- デフォルト６０分未満か指定された最大期間より古くないクエリ
- 現在の実行とまったく同じ結果構成を持つ実行
- クエリで参照されているすべてのテーブルにアクセス可能
- 前の結果が保存されている S3 ファイルの場所にアクセス可能

これらの条件のいずれかが満たされない場合、Athena はキャッシュされた結果を使用せずにクエリを実行する。

## 考慮事項と制限事項
クエリ結果の再利用機能を使用する場合は、次の点に注意が必要。
- 同じワークグループ内でのみクエリ結果を再利用される。
- 行と列の権限を持つテーブルはサポートされない。
- 外部 Hive メタストアを参照するクエリはサポートされない
- 以前に生成された出力ファイルを再利用するための Amazon S3 読み取りアクセス許可が必要
- クエリ結果の再利用機能は、以前の結果の内容が変更されていないことを前提としています。 Athena は、使用前に以前の結果の整合性をチェックしない
- 古い結果が返される可能性があります。 Athena は、指定した最大再利用期間に達するまでソース データの変更をチェックしない。
- 再利用できる結果が複数ある場合、Athena は最新の結果を使用。
- rand() や shuffle() などの非決定論的演算子または関数を使用するクエリは、キャッシュされた結果を使用しない。
    - たとえば、ORDER BY を使用しない LIMITなどキャッシュされない。
    - ORDER BY を使用する LIMITはキャッシュされます。
- Apache Iceberg テーブルでクエリ結果を再利用することはできない。

# 実践
## 事前準備
### ワークグループの作成
Engine V3のを作成します。
- V3 Engine
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/f5b50c48-9d32-4869-cae1-a061e423e42e.png)

### データベースの作成
```
create database reuse;
```
### テーブルの作成
```
root
 |-- order_date: string (nullable = true)
 |-- order_parts_id: string (nullable = true)
 |-- order_num: integer (nullable = true)
 |-- customer_id: string (nullable = true)
```

```
CREATE EXTERNAL TABLE reuse.`order`(
  `order_date` string,
  `order_parts_id` string,
  `order_num` int,
  `customer_id` string)
PARTITIONED BY (
  date string)
ROW FORMAT SERDE
  "org.openx.data.jsonserde.JsonSerDe"
STORED AS INPUTFORMAT
  "org.apache.hadoop.mapred.TextInputFormat" 
OUTPUTFORMAT
  "org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat"
LOCATION
  "s3://{バケット名}/orders-part/"
TBLPROPERTIES (
  'partition_filtering.enabled'='true'
)
```

### パーティションの作成
```
MSCK REPAIR TABLE `order`;
```

## ReUseを検証
Engine V3が選択されているWorkgroupを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/e48f0df0-a343-41ea-2538-e82544b5880a.png)

Re Useを有効化します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/3c972fd0-402e-aadc-30e6-4c57f7df72d6.png)

### 一回目
```
SELECT * FROM "reuse"."order" where "date" = '2022-10-01'
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/7ba22634-5c4a-e893-abd8-d6ffe3180bf6.png)

### 二回目（同一クエリを再度実行）
193ミリ秒でかえってきました。スキャンデータは「-」になっています。
```
SELECT * FROM "reuse"."order" where "date" = '2022-10-01'
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/36d5984e-3f4b-0ccd-a3b0-3feddcd2eb4d.png)

### 別クエリを実行
Whereの条件を10/1から10/2に変更しました。
初回なので10秒程度かかりました。
```
SELECT * FROM "reuse"."order" where "date" = '2022-10-02'
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/bb25041f-c110-279d-bd1d-5fba58e1ec56.png)

### 二回目実行
問題なく高速に実行されました。
```
SELECT * FROM "reuse"."order" where "date" = '2022-10-02'
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/e16796a0-296a-cdfc-c1e5-a9984177aae7.png)


# 考察
ReUseを利用することでAthenaでもミリSecで返されます。定型化されたクエリには有効そうです。

# 参考
https://aws.amazon.com/about-aws/whats-new/2022/11/amazon-athena-query-result-reuse-accelerate-queries/

https://docs.aws.amazon.com/ja_jp/athena/latest/ug/reusing-query-results.html