3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

S3ファイルの大量コピーは、AthenaのINSERT INTOでやると高速(1案として)

Last updated at Posted at 2021-05-10

s3で、大量のファイル(10万とか)をコピーしたい時、どうされていますか?
*ディレクトリ名をちょっと変えたいとかで、大量のディレクトリとファイルがある場合

boto3でプログラム組んで、コピーしようとしたら、ゾッとする遅さでした。
管理コンソール上で数秒で終わるコピーが、何分もかかるとは、思わなかった・・・

今回の方法は、やや制約(gzipになる、HIVE形式でディレクトリ出力される)は発生しますが、同じ溝にはまった人はご参考までに。

s3で大量コピー:boto3(python)の場合

boto3 pythonで実行したところ、100ファイルごとに30秒前後かかっていて、震えました。。。
目の前の25万ファイルを目にして。

30秒×25万ファイル=2083時間 = 87日 もかかる・・・

Athenaでやってみた

どうしようか、、、と考えて、思いついた方法

「AthenaのINSERT INTOを使おう!」

という話です。

[手順]

(1) COPY元のテーブルを作成 
 (ディレクトリをパーティションに指定)

  • コツ: テーブルカラムはstringに統一した方が面倒がないかも

(2) COPY元のパーティションを追加してください。
MSCK REPAIR TABLEは超遅いから、 ALTER TABLEでやりましょう。
例えば、日付("dt", YYYYMMDD形式)をパーティションキーにする場合のコードを載せておきます。

from datetime import datetime , timedelta

start_day = datetime.strptime('2020-10-15','%Y-%m-%d') #例えば2020/10/15 ~ 
last_day = datetime.strptime('2021-05-10','%Y-%m-%d')  # 2021/5/10までのデータをコピーする時

q = 'ALTER TABLE old_table ADD IF NOT EXISTS' # q に ALTER TABLEが入る
part = " PARTITION (dt='{dt}') LOCATION 's3://bucket/path/to/{dt}/'"
dts = []  # ここには、100パーティションの "dt in ({parttion})" に指定するリストが入る
key = []
ctr = 0
while start_day.timestamp() <= last_day.timestamp():
    ctr +=1
    d = start_day.strftime('%Y%m%d')
    q += part.format(dt=d)
    key.append("'{}'".format(d))

    start_day += timedelta(days=1)
    if ctr >=100:
        dts.append(",".join(key))
        key = []
        ctr = 0
if ctr >0:
    dts.append(",".join(key))

(3) COPY先のテーブルを作成 
 (ディレクトリをパーティションに指定)
 * [制約]HIVE形式( /dt=xxxx/ になる)
 * [制約]出力はgzip形式になる
  
(4) パーティション数が100以上になる場合は、100単位で分割
Athenaは一気に100パーティション以上扱えないらしい。
 だから、パーティション100個分ずつ、実行する必要がある。

(5) INSERT INTOを実行
・一応重複がないように、ファイル名が一致したら取り込まないようにする
[追記/訂正] こちら、new."$path"としてますが、ファイル名変わるのでカラムとして取り込まないとダメでした。すいません。

INSERT INTO new_table (select old.* from old_table as old left join new_table as new on egexp_extract(old."\$path", '[^/]+$') = regexp_extract(new."\$path", '[^/]+$') where new."$path" is null and dt in ('20201015','20201016' )

[結果]

-> ざっくりですが、250ディレクトリ、 25万件ほどのファイルコピーが実行3回(合計、15分くらい)で終わった。

よかった。。。

Athenaって便利ですね。
他にも方法があるのかもしれませんが。

3
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?