1. kunit

    No comment

    kunit
Changes in body
Source | HTML | Preview

はじめに

この記事は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ヶ月間=150日とすると、150テーブルをつかうので、10MB * 150で 1.5GB

結論

日付ごとにテーブルを分けるより、Partitioned Tables を使いましょう。

だらだらと書きましたが、BigQueryは正直びっくりするくらい費用がかからないサービスだと思います。
(未だに BigQuery をググると溶かす記事になるのが悔しいなと思うくらいです・・・)

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