GoogleCloudPlatform
BigQuery

BigQueryのクエリー料金の些細な話

More than 1 year has passed since last update.


はじめに

この記事はGoogle Cloud Platform(1) Advent Calendar 2016 の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 は同じになりますが、これがずれるパターンがあるということになるということです。

実は、クエリー料金の計算にはもう一つあまり気にされていないルールがあります。

オンデマンド料金


料金は 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 を使いましょう。

だらだらと書きましたが、BigQueryは正直びっくりするくらい費用がかからないサービスだと思います。

(未だに BigQuery をググると溶かす記事になるのが悔しいなと思うくらいです・・・)

ほんの少し、BigQueryの気持ちになって使えば、お安く気軽に使えるサービスだと思うので、がんがん使うのがいいと思います!