web-dev-qa-db-ja.com

非パーティションテーブルからパーティションテーブルへの移行

6月にBQチーム 日付分割テーブルのサポートが発表されました 。しかし、このガイドには、パーティション化されていない古いテーブルを新しいスタイルに移行する方法が欠けています。

いくつかのテーブルまたはすべてではないにしても新しいテーブルに更新する方法を探しています。

また、パーティション分割されたDAYタイプの外には、他にどのようなオプションがありますか? BQ Web UIからそのような新しいパーティションテーブルを作成できなかったため、BQ UIにこれが表示されますか?.

14
Pentium10

pavanの回答から:この方法では、クエリを実行する回数だけ、クエリのソーステーブルのスキャンコストが請求されることに注意してください。


from Pentium10のコメント:そのため、数年分のデータがあり、毎日異なるクエリを準備してすべて実行する必要があるとします。また、履歴に1000日あるとします。ソーステーブルからクエリ価格全体の1000倍を支払う必要がありますか?

ご覧のとおり、ここでの主な問題は、毎日、完全にスキャンすることです。残りはそれほど問題ではなく、どのスクリプトでも簡単にスクリプト化できます 選択したクライアント

だから、以下は-毎日のフルテーブルスキャンを回避しながらテーブルを分割する方法ですか?

以下のステップバイステップはアプローチを示しています

実際のユースケースに拡張/適用するのに十分一般的です-その間、私は_bigquery-public-data.noaa_gsod.gsod2017_を使用していて、それを読みやすくするために「エクササイズ」を10日間に制限しています

ステップ1–ピボットテーブルを作成します
このステップでは、
a)各行のコンテンツをレコード/配列に圧縮します
そして
b)それらすべてをそれぞれの「毎日」の列に入れる

_#standardSQL
SELECT
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170101' THEN r END) AS day20170101,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170102' THEN r END) AS day20170102,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170103' THEN r END) AS day20170103,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170104' THEN r END) AS day20170104,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170105' THEN r END) AS day20170105,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170106' THEN r END) AS day20170106,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170107' THEN r END) AS day20170107,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170108' THEN r END) AS day20170108,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170109' THEN r END) AS day20170109,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170110' THEN r END) AS day20170110
FROM (
  SELECT d, r, ROW_NUMBER() OVER(PARTITION BY d) AS line
  FROM (
    SELECT 
      stn, CONCAT('day', year, mo, da) AS d, ARRAY_AGG(t) AS r
    FROM `bigquery-public-data.noaa_gsod.gsod2017` AS t 
    GROUP BY stn, d
  ) 
)
GROUP BY line  
_

上記のクエリを、pivot_table(または任意の名前)を宛先としてWeb UIで実行します。

ご覧のとおり、ここでは10列のテーブルを取得します。1日1列で、各列のスキーマは元のテーブルのスキーマのコピーです。

enter image description here

ステップ2–パーティションを1つずつ処理して、それぞれの列をスキャンするだけ(フルテーブルスキャンは行いません)–それぞれのパーティションに挿入

_#standardSQL
SELECT r.*
FROM pivot_table, UNNEST(day20170101) AS r
_

Mytable $ 20160101という名前の宛先テーブルを使用して、Web UIから上記のクエリを実行します。

翌日も同じように走れます

_#standardSQL
SELECT r.*
FROM pivot_table, UNNEST(day20170102) AS r
_

これで、宛先テーブルがmytable $ 20160102などになるはずです。

enter image description here

任意のクライアントでこの手順を自動化/スクリプト化できる必要があります

上記のアプローチを使用する方法には多くのバリエーションがあります-それはあなたの創造性次第です

注:BigQueryはテーブルに最大10000列を許可するため、ここでは1年の各日に365列は問題になりません:o)新しいパーティションに戻ることができる距離に制限がない限り、私は聞いた(しかしまだ確認する機会がありません)過去90日以内です

更新

注意:上記のバージョンには、集約されたすべてのセルをできるだけ最終的な行数にパックするという、少し余分なロジックがあります。

ROW_NUMBER() OVER(PARTITION BY d) AS line
その後
_GROUP BY line_
に加えて
ARRAY_CONCAT_AGG(…)
これを行います

これは、元のテーブルの行サイズがそれほど大きくない場合にうまく機能するため、最終的な合計行サイズは、BigQueryが持つ行サイズの制限内に収まります(現時点では10 MBと考えています)。

ソーステーブルの行サイズが既にその制限に近い場合–調整後のバージョンを使用してください

このバージョンでは、各行に1つの列の値のみが含まれるようにグループ化が削除されています

_#standardSQL
SELECT
    CASE WHEN d = 'day20170101' THEN r END AS day20170101,
    CASE WHEN d = 'day20170102' THEN r END AS day20170102,
    CASE WHEN d = 'day20170103' THEN r END AS day20170103,
    CASE WHEN d = 'day20170104' THEN r END AS day20170104,
    CASE WHEN d = 'day20170105' THEN r END AS day20170105,
    CASE WHEN d = 'day20170106' THEN r END AS day20170106,
    CASE WHEN d = 'day20170107' THEN r END AS day20170107,
    CASE WHEN d = 'day20170108' THEN r END AS day20170108,
    CASE WHEN d = 'day20170109' THEN r END AS day20170109,
    CASE WHEN d = 'day20170110' THEN r END AS day20170110
FROM (
    SELECT 
        stn, CONCAT('day', year, mo, da) AS d, ARRAY_AGG(t) AS r
    FROM `bigquery-public-data.noaa_gsod.gsod2017` AS t 
    GROUP BY stn, d
)
WHERE d BETWEEN 'day20170101' AND 'day20170110'
_

ご覧のとおり、ピボットテーブル(sparce_pivot_table)は十分にスパース(21.5 MBは同じですが、pivot_tableの114,089行と11,584行)なので、最初のバージョンでは平均行サイズが190Bと1.9KBになります。これは、例の列数ごとに明らかに約10分の1です。
このアプローチを使用する前に、何をどのように実行できるかを予測/推定するために、いくつかの数学を実行する必要があります!

enter image description here

それでも、ピボットテーブルの各セルは、元のテーブルの行全体の一種のJSON表現です。元のテーブルの行の場合の値だけでなく、スキーマも含まれている

enter image description here

そのため、それはかなり冗長です-したがって、セルのサイズは元のサイズよりも数倍大きくなる可能性があります[これにより、このアプローチの使用が制限されます...さらに創造的にならない限り:o)...これはまだ十分な領域です適用する:o)]

14

BigQueryで新機能がロールアウトされるまで、 Cloud Dataflow を使用してテーブルを分割する別の(はるかに安価な)方法があります。数百のSELECT *ステートメントを実行する代わりに、このアプローチを使用しました。

  1. 通常のpartitionコマンドを使用して、BigQueryでパーティション分割テーブルを作成します
  2. Dataflowパイプラインを作成し、BigQuery.IO.Readシンクを使用してテーブルを読み取ります
  3. Partition変換 を使用して各行を分割します
  4. 一度に最大200のシャード/シンクを使用して(それ以上で、API制限に達した場合)、パーティションデコレーター構文を使用して対応するパーティションに書き込む日/シャードごとにBigQuery.IO.Writeシンクを作成します-"$YYYYMMDD"
  5. すべてのデータが処理されるまでN回繰り返します。

Githubの例を示します はじめに.

Dataflowパイプラインの料金は引き続きかかりますが、BigQueryで複数のSELECT *を使用するコストのほんの一部です。

7
Graham Polley

今日から、クエリを実行してパーティション列を指定することで、非パーティションテーブルからパーティションテーブルを作成できるようになりました。元の(パーティション化されていない)テーブルに対する1回のフルテーブルスキャンの料金がかかります。 :これは現在ベータ版です。

https://cloud.google.com/bigquery/docs/creating-column-partitions#creating_a_partitioned_table_from_a_query_result

クエリ結果からパーティション分割テーブルを作成するには、結果を新しい宛先テーブルに書き込みます。分割テーブルまたは非分割テーブルのいずれかをクエリすることで、分割テーブルを作成できます。クエリ結果を使用して、既存の標準テーブルを分割テーブルに変更することはできません。

6
Graham Polley

今日、日付分割テーブルがある場合は、このアプローチを使用できます。

https://cloud.google.com/bigquery/docs/creating-partitioned-tables#converting_dated_tables_into_a_partitioned_table

パーティション分割テーブルに変換する単一の非パーティション分割テーブルがある場合、大きな結果を許可してSELECT *クエリを実行し、テーブルのパーティションを宛先として使用する方法を試すことができます(パーティション):

https://cloud.google.com/bigquery/docs/creating-partitioned-tables#restating_data_in_a_partition

この方法では、クエリを実行する回数だけ、クエリのソーステーブルのスキャンコストが請求されることに注意してください。

このシナリオを今後数か月で大幅に改善するための作業を行っています。

4
Pavan Edara

私にとってうまくいくのは、ビッグクエリに直接適用される次のクエリのセットです(ビッグクエリは新しいクエリを作成します)。

CREATE TABLE (new?)dataset.new_table PARTITION BY DATE(date_column) AS SELECT * FROM dataset.table_to_copy;

次に、次のステップとしてテーブルを削除します。

DROP TABLE dataset.table_to_copy;

私はこのソリューションを https://fivetran.com/docs/warehouses/bigquery/partition-table から取得しました。

3
GuenPa