BigQueryでお金を溶かさないコツ

BigQueryは従量課金なので、下手なクエリを打って無駄にお金を溶かしたくはないものです。

操作ミスで高いクエリを実行してしまう大きな理由として、パーティション指定のし忘れがあると思います。

パーティション指定をし忘れを防ぐ為に、トラウマになるぐらいのパーティションを指定する反復練習をするのも一つの手ですが、パーティションを指定しないとクエリが実行されない設定をするという手もあります。

下記のように「–require_partition_filter」を指定してテーブルを作成した上で、

bq mk --require_partition_filter --time_partitioning_type DAY {DATASET}.{TABLE} {SCHEMA}.json

クエリを実行すると、

bq query --nouse_legacy_sql "SELECT * FROM \`{DATASET}.{TABLE}\`

このように怒られます。

Cannot query over table '{DATASET}.{TABLE}' without a filter over column(s) '_PARTITION_LOAD_TIME',
'_PARTITIONDATE', '_PARTITIONTIME' that can be used for partition elimination

これで安心してクエリが叩けますね。

にしても、パーティション指定って面倒臭いですよね。

パーティション指定をした上で、WHERE句に時系列のカラムを指定するとか、パーティションを指定してバルクインサートするとか。

そんな方には「–time_partitioning_field {カラム名}」を指定してテーブルを作成するのがオススメです。

bq mk --require_partition_filter --time_partitioning_type DAY --time_partitioning_field timestamp {DATASET}.${TABLE} {SCHEMA}.json

仮に指定したカラムを下記のテーブルのtimestampにしたとしましょう。

[
  { "name" : "timestamp", "type" : "TIMESTAMP", "mode" : "NULLABLE" },
  { "name" : "user_id", "type" : "INT64", "mode" : "NULLABLE" }
]

まず作成したテーブルに下記のCSVをバルクインサートしてみます。

2018-10-20 12:00:00, 123
2018-10-21 12:00:00, 456
2018-10-22 12:00:00, 789
bq load {DATASET}.${TABLE} xxx.csv

すると、timestampを軸にパーティショニングがされて、 下記のようにloadされます。

{DATASET}.${TABLE}\$20181020 に 「2018-10-20 12:00:00, 123」 {DATASET}.${TABLE}\$20181021 に 「2018-10-21 12:00:00, 456」 {DATASET}.${TABLE}\$20181022 に 「2018-10-22 12:00:00, 789」

さらにそのデータに対して下記のようにクエリを実行すると、

bq query --nouse_legacy_sql "SELECT * FROM \`{DATASET}.{TABLE}\` WHERE timestamp >= TIMESTAMP('2018-10-20') AND timestamp < TIMESTAMP('2018-10-21')

パーティション指定が不要で、しかもパーティションの20181020のみを参照してくれます。

テーブル作成の指定により、実装の工数やクエリの文字数など削減できると思うので、 考慮して指定してみるといいと思います。