【AWS Athena】クエリ実行結果を高速に取得する v2【Python】

# はじめに
Python3上でSQLを書き、[awswrangler](https://pypi.org/project/awswrangler/)を使用してデータを取得する方法を紹介します。
タイトルの「高速に取得する v2」ですが、以前書いた記事

[【AWS Athena】クエリ実行結果のデータを高速にPandas.DataFrameとして取得する](https://qiita.com/nijigen_plot/items/02051f09eee3a2dee2c2)

の続編的な形になるため、そのように書いています。
Python3上でSQLを書いてデータを取得するときは、**pyathenaよりawswranglerのほうが圧倒的に早いよ** ということを書きたいというのが趣旨です。


# 環境・使用ライブラリ

2種類あります
それぞれ箇条書きのリンク先は実際に計測したcolaboratoryとなっています

## colaboratory (Python 3.7.12)

- [pyathena側](https://colab.research.google.com/drive/1Wjw2ARgvhAccQZSdPiAeOujFWjO_HzPC?hl=ja#scrollTo=gzm70Um0MW1J)
    - pyathena==2.3.0
    - pandas==1.3.4


- [awswrangler側](https://colab.research.google.com/drive/1nc58vbLlpzR2Hcmk0P47SwvOP5EP4sLz?hl=ja#scrollTo=jS_lWiN60aZ5)
    - awswrangler==2.12.1
    - pandas==1.3.4
    - boto3==1.20.13


# 結果

500万行10列のデータを**50.8秒**（ctas_approach=True）で展開することができました
ctas_approach=Falseの場合でも**1分26秒**でした

pyathenaライブラリを使用した場合、**24分38秒**もかかってしまいました

# データ取得方法

[環境・使用ライブラリ](#環境・使用ライブラリ)にも実際のcolaboratoryリンクを貼っていますが、awswranglerでのデータ取得方法をこちらにも記載します
[boto3](https://pypi.org/project/boto3/).SessionにAWSの秘密鍵やリージョン情報を記載して、awswranglerを動かします

```python:python
import awswrangler as wr
import boto3
import pandas as pd

# boto3.Sessionへ秘密鍵とリージョンを記載する
session = boto3.Session(
    aws_access_key_id=access,
    aws_secret_access_key=secret,
    region_name = 'ap-northeast-1'
)

# データを取得する(ctas_approach = True)
df = wr.athena.read_sql_query("SELECT * FROM big_parquet_data", database="main_data", boto3_session=session)

# データを取得する(ctas_approach = False)
df = wr.athena.read_sql_query("SELECT * FROM big_parquet_data", database="main_data", boto3_session=session, ctas_approach=False)

# データを取得する s3出力先やワークグループがある場合
df = wr.athena.read_sql_query(
    "SELECT * FROM big_parquet_data", database="main_data",
     boto3_session=session, workgroup='workgroup', s3_output='s3://*******'
)
```

read_sql_queryのその他引数についてはこちらに記載されています
https://aws-data-wrangler.readthedocs.io/en/stable/stubs/awswrangler.athena.read_sql_query.html

## ctas_approachについて

Trueにすると、s3からparquetとして読み込むため**大規模なデータのダウンロードスピードが速く**なります。
ただし、AWS Glueでテーブルの作成/削除権限が別途必要です。その分料金も別で掛かります。

Falseにすると、単一のcsvから読み込むためTrueの時よりは大規模なデータのダウンロードスピードが遅くなります。（それでも速い）
AWS Glueの権限は必要ありません。


## Windows環境での文字化け対処

文字エンコードの関係で、`ctas_approach=False`の状態でcsvを読み込むと、文字化けしたり

```
 'cp932' codec can't decode byte 0x86 in position 29: illegal multibyte sequence
```


等と、エラーが出ることがあります。

pyathenaと違い、データを取得する際にpandasを使用しないので、エンコード方法を指定することができません。
そこで、実行前に以下のコードを実行すると、WindowsがデフォルトでUTF-8エンコードとなり、文字化けやエラーを回避することができます。

```python:文字化け直しコード
import os
if os.name == 'nt':
    import _locale
    _locale._getdefaultlocale_backup = _locale._getdefaultlocale
    _locale._getdefaultlocale = (lambda *args: (_locale._getdefaultlocale_backup()[0], 'UTF-8'))
```


### 対処例

日本語の入ったデータを作って、比較してみます

```sql:sql
CREATE TABLE main_data.name_list AS
SELECT * FROM (
    VALUES
        (1, '田中'),
        (2, '佐藤'),
        (3, '大森')
) AS t (id, name)
```


```python:対処前
display(wr.athena.read_sql_query("SELECT * FROM name_list", database="main_data", boto3_session=session, ctas_approach=False))
```

| | id | name |
| --- | --- | --- |
|0|1|逕ｰ荳ｭ|
|1|2|菴占陸|
|2|3|螟ｧ譽ｮ|


```python:対処後
import os
if os.name == 'nt':
    import _locale
    _locale._getdefaultlocale_backup = _locale._getdefaultlocale
    _locale._getdefaultlocale = (lambda *args: (_locale._getdefaultlocale_backup()[0], 'UTF-8'))

display(wr.athena.read_sql_query("SELECT * FROM name_list", database="main_data", boto3_session=session, ctas_approach=False))
```

| | id | name |
| --- | --- | --- |
|0|1|田中|
|1|2|佐藤|
|2|3|大森|

文字化けを解消することができました！

# 最後に

大規模データのダウンロードもこれで快適です！
更に改善点などあれば教えていただけると助かりますm(__)m