バケッティングとは
Athenaでは費用を抑えつつ、クエリの高速化を図るための代表的な手段としてパーティションがあります。
しかし、パーティションに加えてバケッティングというやり方もあるのでそのやり方と注意点を記載しておきます。
バケッティングというとS3のバケットが出てくるかもしれませんが、それとは全く別の概念です。
CTASでパーティション分割してテーブルを作成する際のデメリットとして100個のパーティションまでしか作成出来ないというデメリットがあります。これは一応INSERT文などでなんどもなんども実行すればなんとかなるという事はあるのですが、かなり実行コストがかかります。
バケッティングのメリット
CTAS クエリ結果のバケット化は、カーディナリティが高く、値が均等に分散されている列によってデータをバケット化するときにうまく機能します
引用元にあるように、カーディナリティが高いものでうまく機能します。
例えばユーザーIDでパーティションを分けようとするとユーザーが1万人などいると、パーティション分割がかなり難しくなります。100回クエリを実行する必要があります。
そこで以下のようなCTAS文を実行します。
CREATE TABLE bucketed_comments
WITH (
format='PARQUET',
external_location='s3://example_bucket/users/bucketed/',
bucketed_by = ARRAY['user_id'],
bucket_count = 100
) AS
select * from comments
コメントテーブルに対してバケッティングを施した新しいテーブルを作成します。bucket_countを100としているので100ファイルに分割されます。
このテーブルに対して
SELECT * FROM bucketed_comments WHERE user_id in (1,3,8);
といったSQLを実行すると、スキャンするファイルがuser_idが1,3,8のデータが存在するファイルだけになります。
つまり100ファイル中最大でも3ファイル、最小で1ファイルのみのスキャンとなります。これがバケッティングもパーティション分割もしていないと100ファイルのスキャンとなります。
デメリットその1 bucket_countの設定をミスらない
ではbucket_countを増やせばそれでいいのか?というと全くそんなことがないのです。
bucket_countを増やすとファイル数が増えます。そうなると例えばuser_idを指定せずにスキャンした場合に、たくさんのS3ファイルにアクセスするためにS3へのリクエスト費用がかかり、かつ速度もかなり遅くなります。
1MBの1ファイルに1リクエストと1KBの1000ファイルに1000リクエストどちらが優れてるかを考えればすぐに分かるかと思います。
したがって、バケッティングに指定したcolumnを確実に指定する、しない場合もあるのであればそれを考慮してcountをいくつにするかを考える必要があります。
Athenaでは1ファイルあたり128MBに調整すると一番パフォーマンスがでるようです。
デメリットその2 INSERT文が使えない
バケッティングを設定したテーブルにはINSERTが使えません。どのファイルにどのデータを入れて置くのかまで考慮しているのがバケッティングなので、今後もここの改善を望むのは難しそうです。
したがって、随時データが増えていくようなテーブルは向いていないかもしれません。例えば日時でデータが増えていくテーブルであれば、パーティションでINSERTで新しい日付のデータを加えていく、といった運用で良さそうです。
最後に
バケッティングはINSERTが使えないという点が一番のデメリットのように感じます。
Athenaを使うのはCSVなどでどんどんデータを加えていけるというのが一つのメリットであるからです。ただ、簡単にスキャン料を減らせるというのが実現できるので、知っておくだけでも、使えるパターンが来たときに大活躍するかもしれません。