はじめに
この記事は[Google Cloud Platform(1) Advent Calendar 2016] (http://qiita.com/advent-calendar/2016/gcp) の11日目の記事として書かれています。
BigQueryのクエリー料金で私がハマった些細(でもない)話を書きたいと思います。
BigQuery の費用のおさらい
某溶かした記事でおなじみの BigQuery ですが、使おうとしている人はもちろん、使っている人たちも一番気にしている部分が「どれくらい費用がかかるのか?」ということになります。
BigQuery では以下のことに費用が発生します。
- ストレージ料金
- データの保存費用、保存した容量に対して費用が発生
- 90日以上使用されていないテーブルは費用がぐっと安くなる
- そもそも、スゲー安い
- steaming insert
- リアルタイムにデータを追加するための費用、転送した容量に対して費用が発生
- 気をつけないとそこそこかかる
- クエリー料金
- スキャンした容量に対して費用が発生(もう少し詳しいことは後述)
- 気をつけないと溶かすことになる
1と2に関してはシステム運用側でコントロールする費用なのである程度予測ができますが、3のクエリー料金に関しては、分析メンバーや営業メンバーにクエリーするインタフェースを開放してたりするとどれくらい費用がかかるか?ということが気が気でない人たちが多数だと思います。
クエリー料金のおさらい
BigQueryのクエリー料金は、以下のようにかかります。
- 実行したクエリーが実行時に使用したカラムの全容量に対して費用発生する
たとえば、カラムが10個あるテーブルがあって、そのテーブルに1億レコード保存していた場合、
- id という INTEGER のカラムがあった場合、SELECT id FROM ... とすると、 8byte * 1億 という容量に対して費用計算される
- これは、LIMIT 1000 としても、1億レコード分スキャンしたことに変わりがないので、費用が安くなることはない
- さらに name という TEXT のカラムがあった場合、 SELECT name FROM ... WHERE id = 1 とすると、
name カラムの1億レコード分の容量と、 条件で使用した id カラムの1億レコード分の容量分に対して費用計算がされる - SELECT * FROM ... なんてことをすると、そのテーブルの全容量分に対して費用計算がされるので、bq使いの人たちから責められる
上記のように、LIMIT でしぼっても、そのカラムの全容量が費用計算の対象となるため、BigQueryを利用している人たちでは、日付ごとにテーブルを分割するというのが常套手段になっています。
例えば、注文テーブルがあった場合、すべてを order テーブルに入れてしまうと、どんどんクエリー料金が膨らんでいくので、
- order_20161201、 order_20161202、 order_20161203、・・・
といったように日付ごとにテーブルを分割し、必要な日付分だけ UNION して集計するということになります。
クエリー容量の2つのパラメータ
BigQueryのクエリーのAPIに関して、クエリー容量に関するパラメータは以下の2つになります。
- statistics.query.totalBytesProcessed
- statistics.query.totalBytesBilled
1 はそのまま、クエリー実行時に使用したバイト数になります。
2 はクエリー料金の費用計算で使用されるバイト数です。
ここまでの説明で、「BigQueryのクエリー料金は、クエリー実行時に使用したバイト数」と説明してきたわけですから、なぜ 1 と 2 が違うのか? という疑問が出てきます。
ほとんどの場合、 1 と 2 は同じになりますが、これがずれるパターンがあるということになるということです。
実は、クエリー料金の計算にはもう一つあまり気にされていないルールがあります。
[オンデマンド料金] (https://cloud.google.com/bigquery/pricing#on_demand_pricing)
料金は MB 単位のデータ処理容量(端数は四捨五入)で決まります。クエリが参照するテーブルあたりのデータ処理容量は最低 10 MB で、クエリあたりのデータ処理容量は最低 10 MB です。
つまり、ものすごく容量が少ないテーブルに対して、クエリーを実行した場合でも、最低 10MB 分の費用がかかるということで、1MBしか容量がないテーブルに対してクエリーを実行した場合、totalBytesProccessed は 1MB といった値になりますが、totalBytesBilled は 10MB となるということになります。
でようやく、私がハマった話
ここまで説明してようやく私がハマった話ができるわけですが、以下のようなことが発生していました。
- テストをするために、ものすごく容量が少ないテーブル群に対してクエリーを発行したらそこそこ料金がかかってしまっていた
- 日付ごとのテーブルを準備(データ量は極少数)
- 3ヶ月間、6ヶ月間といった、期間毎の集計を行うテストをしていた
この原因を突き詰めていくと、
- クエリーの費用計算の最低容量の 10MB というのは、「テーブルあたり」である
つまり、各テーブルの容量がものすごく少なくても以下のような容量に対して、費用計算が発生します。
- 3ヶ月=90日とすると、90テーブルをつかうので、10MB * 90で 900MB
- 6ヶ月間=180日とすると、180テーブルをつかうので、10MB * 180で 1.8GB
結論
こういうことが気になるならば、[Partitioned Tables] (https://cloud.google.com/bigquery/docs/partitioned-tables) を使いましょう。
だらだらと書きましたが、BigQueryは正直びっくりするくらい費用がかからないサービスだと思います。
(未だに BigQuery をググると溶かす記事になるのが悔しいなと思うくらいです・・・)
ほんの少し、BigQueryの気持ちになって使えば、お安く気軽に使えるサービスだと思うので、がんがん使うのがいいと思います!