25
10

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 5 years have passed since last update.

BigQueryのテーブル分割でのパーティションテーブルとシャーディングテーブルの使い分け

Last updated at Posted at 2019-04-25

TL;DR

原則としてパーティションテーブルを使うが、上位互換ではないため1次保存層にはシャーディングテーブルを使う
マサカリください

概要

データ分析を行う際には分析基盤の整備が欠かせません
分析基盤としては様々なプロダクトがありますが、そのなかでBigQueryには下記の利点があります

  • よく使われるため分析者にとって馴染み深い
  • 処理が分散実行されるためとても高速
  • GCPのフルマネージドであるため運用が楽

ここではデータ加工層(データマート、データウェアハウス)だけでなく、1次保存層(データレイク)としてもBigQueryを用いる場合について考えます
※データの3層構造に関しては下記記事の思想に従います
http://yuzutas0.hatenablog.com/entry/2018/12/02/180000

あなたが格納しようとしているデータが日毎に増えていくような大規模データであるとしましょう
1つの大きなテーブルにすべてを入れてしまうと毎回フルスキャンをしてしまい課金額が恐ろしいことになります。そのためデータを分割する必要があるのですが、いくつかある方法のなかからどれを使うべきかを考察します

3種類の分割方法

BigQueryのテーブル分割方法は新しい順に下記3つの方法があります

  • パーティションテーブル(分割テーブル)のうち、分割カラムを自分で指定するもの
  • パーティションテーブル(分割テーブル)のうち、取り込み時間で分割するもの
  • シャーディングテーブル(日付別テーブル)

ドキュメントは下記です
https://cloud.google.com/bigquery/docs/partitioned-tables
それぞれの説明については下記記事にまとまっています
https://qiita.com/mokrai/items/3eaa57e700ac084d33d8

このうち、2番目の取り込み時間で分割するパーティションテーブルは今から選択するメリットが無さそうです
元データをどこかから連携してBigQueryに入れるわけですが、連携処理には遅延が発生しえます。取り込み時間でパーティションを分けてしまうと本来入るべきだったパーティションとは別のパーティションに入る可能性があります。1番目の方法で適切な時間カラムをパーティションに用いたほうがよいでしょう

1番目の方法と3番目の方法は一長一短であるため利点と欠点について考えます

それぞれの利点と欠点

パーティションテーブル(分割テーブル)

パーティションテーブルはデータを日付ごとに分割してパーティションで区切り、1つのテーブルに入れる方法です
シャーディングテーブルの問題点を解決すべく後から作られました。そのため原則的にはこちらを推奨するとドキュメントに書いてありますが、制約もあります
https://cloud.google.com/bigquery/docs/partitioned-tables#partitioning_versus_sharding

pros

  • 処理が最適化されるためにクエリの実行速度が速い
  • 日付ごとに異なるスキーマを適用できない。そのため利用者側はカラムが日付ごとに変更される可能性を考慮しなくて良い

cons

  • 1つのテーブル内のパーティション数には上限がある(現在は4000) ※実は4080くらいまで入るのを確認しました。本当の上限は4092とかかもしれません
  • 日付ごとに異なるスキーマを適用できない。そのためデータソースでカラムが増減した場合、無視するか何らかの工夫が必要

パーティション制限に関しては昔2000だったのが4000に増量された実績があります。そのため今後googleが良きタイミングで増量してくれる可能性がありますが、あなたのデータの限界には間に合わないかもしれません
パーティション制限を回避しようとすると例えば10年ごとにテーブルを分けることが考えられますが、下記理由により多少煩雑になります

  • CUIだけでなくGUIからも複数のテーブルに分かれて見える
  • 例えば2000年代、2010年代、2020年代とテーブルを分けると、ワークフローエンジンが2020/1/1の処理で新規にテーブルを作るが、何かあった場合正月休みが爆発するかも

シャーディングテーブル(日付別テーブル)

シャーディングテーブルとはデータを日付ごとに別のテーブルとして作成する方法です。BigQueryのGUIからはひとつのテーブルとしてまとめられて見えます

pros

  • 日付ごとに異なるスキーマを適用できる。そのためデータソースでカラムが増減した場合でもそのまま取り込める

cons

  • 日付ごとに異なるスキーマを適用できる。利用者としてはカラムの不一致により日をまたいだクエリが失敗する可能性がある ※どのみちデータの特性は利用者でも把握する必要があるとも言えます
  • BigQueryのUI上ではシャーディングされたテーブルはまとめられるものの、CUIや他ツール(Tableauなど)連携の場合にまとめられておらず、日付テーブルごとに全部出てしまうので見づらい
  • 日付をまたいだクエリを書きたい場合、ワイルドカードテーブルという書き方を使いますが下記制約・注意事項があります
    • ビューのなかでワイルドカードテーブルを使うことができない
    • ワイルドカードテーブルを用いたクエリはキャッシュされない
    • GUIで合計クエリ容量が出てくるまで時間がかかる場合がある ※1
    • ワイルドカードは単純な末尾マッチなので誤爆がありえる ※2

ワイルドカードテーブルクエリの制約のドキュメントは下記になります
https://cloud.google.com/bigquery/docs/querying-wildcard-tables#limitations
ワイルドカードテーブルでスキャン範囲を絞るためには_TABLE_SUFFIXを用います
https://cloud.google.com/bigquery/docs/querying-wildcard-tables#filtering_selected_tables_using_table_suffix

※1
GUIの合計クエリ容量というのは下記の様にクエリの課金対象のデータ量が右下に表示されるのですが、この値が出るまでに時間がかかる場合があります
スクリーンショット 2019-04-25 15.26.37.png

※2
例えばdataset.product_*と書くとdataset.product_20190425だけでなくdataset.product_special_20190425にもヒットします
この問題はテーブル名と日時の区切り文字を特別なものにし、dataset.product__20190425のようにするプラクティスで回避可能です

どちらを使うべきか

焦点としては

  • パーティション数の上限の存在
  • 異なるスキーマを適用できるかの仕様の違い
  • パフォーマンスと運用上の利点

になるのではないかと思います
データウェアハウス・データマート層に関しては、パフォーマンスと運用上の利点からパーティションテーブルを用いたほうが使い勝手が良いと思います
一方でデータレイク層に関しては、データを貯蔵するという特質からデータを保存する確実性を重視し、シャーディングテーブルを用いたほうが良いのではないかと考えています

最後に

上記の考えは現時点での個人的な考えです。何かあればマサカリを投げていただけるとありがたいです

25
10
0

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
25
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?