bigquery中のテーブルの列の削除について、RECORD型のフィールドへの注意

(これはメモ。全体的にふわっとしている)

スキーマの変更が必要になったときの対応について調べたりなどしていた。 色々方法を眺めて見たところ、alter tableを使った方法が使用感的には個人的には一番しっくり来た1。が、機能が制限されているらしい。

その方法などのメモと他の方法のメモ。

alter table

alter tableを使った列の削除は以下の様な形で書く。

ALTER TABLE <table name>
  DROP COLUMN IF EXISTS <column 1>,
  DROP COLUMN IF EXISTS <column 2>,
  ...

しかし、これはテーブルのトップレベルの列には対応しているものの、RECORD型の持つフィールドまでは対応してくれないらしい(列ではない扱いなので当然といえば当然かもしれない)。

実際のところ以下の様に注意書きが書かれている。

このステートメントで次の列のドロップはできません。

悲しい。とりあえず、現在のところは古いフィールドを残したままにしておく運用にしておいてみる2

テーブルへのデータの入れ替え

それではと新しいテーブルへのデータの入れ替えする方法は以下の様なものがあるらしい。

前者はフルスキャンが走る。後者は大きなテーブルでは結構厳しい。

此処には、列を削除するときのことも書かれているのだけれど、気になる記述がある。

手動で列を削除するには、次の 2 つの方法があります。

  • SQL クエリの使用 - わかりやすさと使いやすさを重視し、費用をあまり重視しない場合は、このオプションを選択します。
  • テーブルの再作成 - 費用を重視し、わかりやすさと使いやすさをあまり重視しない場合は、このオプションを選択します。

そしてクエリーの使用するの部分で以下のような記述がある。

列の削除に使用できる SQL ステートメントは 2 つあります。

  • SELECT * EXCEPT
  • ALTER TABLE DROP COLUMN

というわけで、ALTER TABLEをやるたびにフルスキャンが走ることになりそう3。おそらくメタデータ的なものを書き換えるだけではなく、裏側ではテーブルの作り直しが走っている(一方で、列の制限の緩和などは一瞬で終わったしメタデータの書き換えだけなように感じた)。

そもそもどうして列を削除したくなるか?

スキーマに不要な列が存在しないほうが見た目がすっきりして良いという話もあるけれど、terraformで管理しているときに、列の削除の差分が走った場合に、inplaceのchangeではなく、destroy and createとして判定されるので。

そのことをtwitterで愚痴ったりしてた

参考


  1. おそらく他のDBMSでのschema migrationと同様の感覚なので

  2. すべてのデータセットを再構成可能とみて特定のタイミングでbigqueryのテーブルを作り直すという運用にしても良い気がするがまだ軽微なのでやっていない

  3. とはいえ、テキトーに SELECT * FROM <table> とかしただけでフルスキャンが走るので目くじらを立てて忌避するほどのものではない気もするけれど