Help us understand the problem. What is going on with this article?

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

More than 3 years have 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の気持ちになって使えば、お安く気軽に使えるサービスだと思うので、がんがん使うのがいいと思います!

kunit
2018年末に福岡に移住して、ロリポップ!、ヘテムル、ムームードメインといったサービスに携わっています とはいえまだまだ修行中...
https://kunit.jp/
pepabo
「いるだけで成長できる環境」を標榜し、エンジニアが楽しく開発できるWebサービス企業を目指しています。
https://pepabo.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away