1. kunit

    Posted

    kunit
Changes in title
+BigQueryのクエリー料金の些細な話
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,96 @@
+# はじめに
+
+この記事は[Google Cloud Platform(1) Advent Calendar 2016] (http://qiita.com/advent-calendar/2016/gcp) の11日目の記事として書かれています。
+
+BigQueryのクエリー料金で私がハマった些細(でもない)話を書きたいと思います。
+
+# BigQuery の費用のおさらい
+
+某溶かした記事でおなじみの BigQuery ですが、使おうとしている人はもちろん、使っている人たちも一番気にしている部分が「どれくらい費用がかかるのか?」ということになります。
+
+BigQuery では以下のことに費用が発生します。
+
+1. ストレージ料金
+ * データの保存費用、保存した容量に対して費用が発生
+ * 90日以上使用されていないテーブルは費用がぐっと安くなる
+ * そもそも、スゲー安い
+2. steaming insert
+ * リアルタイムにデータを追加するための費用、これも転送した容量に対して費用が発生
+ * 気をつけないとそこそこかかる
+3. クエリー料金
+ * スキャンした量料に対して費用が発生(もう少し詳しいことは後述)
+ * 気をつけないと溶かすことになる
+
+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つになります。
+
+1. statistics.query.totalBytesProcessed
+2. 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ヶ月間=150日とすると、150テーブルをつかうので、10MB * 150で 1.5GB
+
+# 結論
+
+日付ごとにテーブルを分けるより、(Partitioned Tables) [https://cloud.google.com/bigquery/docs/partitioned-tables] を使いましょう。
+
+だらだらと書きましたが、BigQueryは正直びっくりするくらい費用がかからないサービスだと思います。
+(未だに BigQuery をググると溶かす記事になるのが悔しいなと思うくらいです・・・)
+
+ほんの少し、BigQueryの気持ちになって使えば、お安く気軽に使えるサービスだと思うので、がんがん使うのがいいと思います!
+
+