BigQueryで速度を出すための仕組み
園芸学部出身エンジニアの @harada_hi です。日本庭園好きです。
PLAID Advent Calendar 2018 の16日目を担当します。
今回はBigQueryをうまく利用するための仕組みの話をしたいと思います
BigQueryの活用箇所と速度改善の必要性
弊社の製品、KARTEではサイト来訪者の行動データを取得しています。
製品の中ではこの行動データをレポーティングする部分などでBigQueryを活用しています。
行動データという特性上、非常に大量のデータがKARTEには存在しています。
BigQueryは大量データの集計も非常に高速に結果を返してくれるわけですが、
テラバイトを優に超えるデータに対して、複雑な集計をかけると流石に結果が返ってくるまでの時間が掛かります。
BigQueryの速度改善について
これに対する解決策としては次の2点があげられます。
1. 集計結果を事前に作りキャッシュとして保存しておく
2. 集計するデータの対象データを絞り込んだ中間テーブルを準備する
基本的には1の方針で検討し、機能内容的に1が難しい場合に2での対応を検討しています。
今回は2の対応を実行した際の問題とその解決策に関してまとめています。
BigQueryはWHERE句やLIMITを考慮せずに最初に全件を読み込みします。
このためWHERE句を指定して処理するデータ量を減らしたと考えていても読み込むデータ量が多ければ速度は遅くなります。
テーブルの行数(データ量)を減らすこと、SELECTする列を減らすことが非常に重要です。
中間テーブルを生成する上での問題点
中間テーブルを作成する上で、BigQueryの 同時実行レート制限 - 50 件の同時クエリ
という点が問題になりました。
BigQueryの制限に関してはGoogleの公式ドキュメントをご参照ください。
https://cloud.google.com/bigquery/quotas?authuser=2&hl=ja
同時実行レート制限が問題になった理由は、次の要因により中間テーブルを作成するクエリの数が多くなったためです。
- 元テーブルはプロジェクト毎に存在する
- 元テーブルは日付で分割されており、中間テーブルも同様の構成にしたい
中間テーブルを定時バッチなどで作成しようとする場合、作成する必要のあるテーブル数分のクエリを実行することになるため同時実行の制限にかからないよう制御する必要が出てきます。
そのため完了までの時間の予測が立てづらく、必要なタイミングに中間テーブルがないという問題が考えられました。
同時実行レート制限を回避するためにprioryをBATCHにして実行するということも選択肢にはありましたが、こちらは24時間以内に実行されることを保証するという仕様のため同様の問題が考えられた形です。
また定時に実行するとしても中間テーブルを用意しておきたい時間には他の処理も多々流れている状態であったため、該当の時間帯に処理を追加しにくい状況でもありました。
問題点を解消する上での仕組み
最終的に次の2点の対応で上記の問題を解消しています。
- ユーザーが中間テーブルを必要とするページに最初にアクセスしたタイミングで中間テーブルを生成する
- その日の中間テーブルが作成されていなかった場合に、その日分の中間テーブルを作成するバッチを設ける
中間テーブルを生成する上での問題点
で記載した内容だけを考慮すると、1の選択肢だけ良いように感じるかと思います。
しかし日付ごとにテーブル分割されているためページアクセスをしていない日が長くなればなるほどアクセス時に作成するテーブル数が増えてしまいます。
これによりレスポンスが遅くなりUXが低下してしまうため、2の対応も併せて行うことでその問題に対応している形です。
また2の対応は、あくまでもテーブルが作られていない場合に処理を回せば良いため、他の処理が集中している時間帯を避けることにも繋がります。
おわりに
今回はBigQueryでパフォーマンスを出すための中間テーブルをプロダクトでどうやって作っているのかという点を紹介しました。
速度改善という点では今回紹介したものは手段の一つであり、状況ごとにそれぞれ最適な手段は異なると考えています。
BigQueryの範囲ですと直近で @tmonoi が紹介している Clustered Table
は活用しどころが多いのではないかと思っております。
https://qiita.com/tmonoi/items/7fab1ba2ef1c88a2fd71