BigQueryのDML（今回はUPDATE）の性能を試してみる。

#BigQueryでDMLが扱えます。
2016年11月よりBigQueryでもStandardSQLがベータ版が提供され、同時にDMLも使えるようになりました。
詳しくは[コチラ](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-manipulation-language)。あと、まだベータ版ですので[制限](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-manipulation-language)もあります。
では、実際にどのぐらい性能が出るのかをみてみたいと思います。

##なんでやるの？
BigQueryはそもそもデータ保管料金がすこぶる安く、またクエリ課金ということもあり過去に紹介した方法（[中村式UPDATEって言われているｗ](http://qiita.com/satoru_mag/items/fb233c188dd63f1aafff)）でVIEWとtimestampを使って最新のデータのみを抽出して、UPDATEっぽいことをやっていました。
これはこれでデータがどのように育ったかを履歴として取ったりするのに、何気に便利で自分も活用しておりました。
しかし、業務データなどでは『データの洗い替え』ということもありますし、10億行×1億行とか膨大な場合はイチイチJOINしているとお金的に痛くなります。データを入れた後に『間違えた！』なんてこともしばしば。。。。
自分も業務で必要だなぁと思ったことがあったのでやってみようと思いました。
##今回使うデータ
今回はBigQueryで公開されている[世界の気象情報](https://bigquery.cloud.google.com/dataset/bigquery-public-data:noaa_gsod?tab=schema)でやってみたいと思います。これには観測地点コードを持っており、そのコードを国名に書き換えるということをやってみます。
まずは、自分のProjectのDatasetに、このDatasetに入っているTableをコピーして使います。

##1行のUPDATE
まずは、ピンポイントでデータを書き換えてみましょう。[gsod1929](https://bigquery.cloud.google.com/table/bigquery-public-data:noaa_gsod.gsod1929?tab=details)は2,081行入っています。
![update_002.jpg](https://qiita-image-store.s3.amazonaws.com/0/49108/a6a9745d-2333-36c8-22f8-aefd7bf50b37.jpeg)

どうやら成功したようです。では本当にUPDATEされているのか見てみましょう。
![update_003.jpg](https://qiita-image-store.s3.amazonaws.com/0/49108/0681ffcc-dc65-7b15-5119-e9993d7ab112.jpeg)

ちゃんとUPDATEされています。想定の範囲内ですね。
1行の更新に約4秒ほどかかっています。普通のクエリと同じような時間だと思われます。
###データが多いテーブルの1行だけの場合は？
さきほどのデータは2000行ということでデータ量が少なかったです。では、データ量が多い場合はどうなのでしょうか？
[gsod2016](https://bigquery.cloud.google.com/table/bigquery-public-data:noaa_gsod.gsod2016)には約430万行ほど入っています。これで実験してみましょう。
![update_004.jpg](https://qiita-image-store.s3.amazonaws.com/0/49108/b7993ac2-6258-a606-86f0-22524ae0d0d0.jpeg)

なるほど。それなりに時間がかかっていますね。データ量に比例して時間もかかるということでしょうか。
また、興味深いのはQuery completeのところでデータ量を見ると**テーブルがフルスキャン**になっていますが、費用自体はこれではありません。まだベータ版ということもあり、ここは後ほど改善されるように思います。

##複数行のUPDATE
実際には1行だけというのは『間違えた。えへっ。』な場合ぐらいしかなく、ほとんどは複数行を一気にアップデートするケースが多いとおもいます。色んなやり方があると思いますが、`SET` のところを指定でやるのとサブクエリを使ったものをテストしてみたいと思います。データ量が多い方（[gsod2016](https://bigquery.cloud.google.com/table/bigquery-public-data:noaa_gsod.gsod2016)）で実験していきます。
###SETを指定する
`SET`を指定してやってみます。`stn = '425000'`は364行あります。
![update_005.jpg](https://qiita-image-store.s3.amazonaws.com/0/49108/0833aac3-4108-8f6c-ae6d-1c6044b8fa68.jpeg)
きちんと出来ているようですね。1行よりも若干時間がかかっているようにも見えますが、これ以外にwhere句の`stn`を何度か変えてやってみると1行とほぼ同等の時間でした。普通のSELECT文でもよくありますが、前後5秒ぐらいは幅があるようです。

次はWHERE句の値を複数指定して、UPDATEする行数を増やしてやってみましょう。`stn`が2から始まるもの（24万行）をすべて書き換えてみます。
![update_006.jpg](https://qiita-image-store.s3.amazonaws.com/0/49108/d3099806-8fa9-7588-0448-4fce8f16f18a.jpeg)
ふむ。更新する行数が増えたところで、時間は変わらないようですね。
###サブクエリを使って更新する
では実際によく利用されている`SET`をサブクエリを利用して更新してみましょう。[station](https://bigquery.cloud.google.com/table/bigquery-public-data:noaa_gsod.stations)には`usaf`と`wban`いう情報があり、これは先程から更新している`gsod2016`の`stn`と`wban`にひもづいています。また、観測地点の情報が入っています。その中に`country`という列がありますので、`stn`をこれに書き換えていきたいと思います。
![update_007.jpg](https://qiita-image-store.s3.amazonaws.com/0/49108/b9de3cee-311b-3b6d-3e4b-421296e0d286.jpeg)
417万行ほど更新が行われました。サブクエリを行ったので、時間が増えたのかな？と思っています。
##テーブルをまたいでのUPDATE
BigQueryにはデータを効率よく管理するために[ワイルドカード テーブル](https://cloud.google.com/bigquery/docs/querying-wildcard-tables)というものがあります。この機能の詳細はここでは省きますが、正規表現や日付でテーブルを指定出来ますので非常に便利です。使われている人も多いのではないでしょうか？
**しかし、これはまだ[対応](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-manipulation-language)されていません。残念。。。。。**

##複数列もやってみる。
一気に複数列を書き換えるというのをやってみましょう。`gsod2016`の`max`には最高気温（華氏）が入っています。
これを摂氏に変換して上書きし、ついでにflag_maxがStringなので、そこには気温によって文言を入れてみましょう。
![update_009.jpg](https://qiita-image-store.s3.amazonaws.com/0/49108/0efc0c24-4b38-5a67-2f05-f7ff75318cb3.jpeg)

出来ました。1列の時間と特に変わりは無いように思います。

#総括
今回はUPDATEを検証してきました。
注意する点としてUPDATEした場合は[long term storageのタイマーがリセット](https://cloud.google.com/bigquery/pricing#long-term-storage)されることです。これは地味に痛いように思います。気をつけてください。

まだベータ版ということもあり、実際のプロダクトで利用するのは難しいかもしれません。しかし、パフォーマンスについては十分に使えるものになっていると思います。テーブルを作り直すよりも速いかもしれません。
また、ついでにやってみたのですが**UPDATEしている最中でもクエリを投げて普通に結果が返ってきます。**よくあるのが、UPDATEしている最中は触るなとか（RDBMSの場合はロックされてUPDATEが終わるまで結果が返ってこないとか）、変な結果が返ってくるとかあるかもしれませんが、そういうことはありませんでした。UPDATEが終わった直後から、それが反映されてきちんとクエリの結果も返ってきます。素晴らしいです。

ということで、色々といぢってExplanationで動きをみながらやっていたのですが、BigQueryらしい更新のやり方だなぁと思いました。
お試しあれ。

#おまけ
複数列でやったクエリをgsodのデータすべて連結してみて2億行の更新を調子にのってやってみました。1分かかってない！
![update_010.jpg](https://qiita-image-store.s3.amazonaws.com/0/49108/0c0617bf-a6ab-374f-7921-e12998d56cab.jpeg)