DML を使用した分割テーブルデータの更新

このページでは、分割テーブルに対するデータ操作言語(DML)のサポートの概要について説明します。

DML の詳細については、次をご覧ください。

この例に使用されているテーブル

次の JSON スキーマ定義は、このページの例で使用されているテーブルを表します。

mytable - 取り込み時間分割テーブル

    [
      {"name": "field1", "type": "INTEGER"},
      {"name": "field2", "type": "STRING"}
    ]

mytable2 - 標準の(パーティショニングされていない)テーブル

    [
      {"name": "id", "type": "INTEGER"},
      {"name": "ts", "type": "TIMESTAMP"}
    ]

mycolumntable - ts TIMESTAMP 列を使用してパーティション分割された分割テーブル

    [
      {"name": "field1", "type": "INTEGER"},
      {"name": "field2", "type": "STRING"}
      {"name": "field3", "type": "BOOLEAN"}
      {"name": "ts", "type": "TIMESTAMP"}
    ]

データの挿入

分割テーブルに行を追加するには、DML の INSERT ステートメントを使用します。

取り込み時間分割テーブルへのデータの挿入

DML ステートメントを使用して取り込み時間分割テーブルに行を追加する場合は、行を追加するパーティションを指定できます。_PARTITIONTIME 疑似列を使用してパーティションを参照します。

たとえば、次の INSERT ステートメントでは、mytable の 2017 年 5 月 1 日のパーティション(“2017-05-01”)に行を追加します。

INSERT INTO PROJECT_ID.DATASET.mytable (_PARTITIONTIME, field1, field2) SELECT TIMESTAMP(“2017-05-01”), 1, “one”

厳密な日付境界に対応するタイムスタンプのみを使用できます。たとえば、次の DML ステートメントではエラーが返されます。

INSERT INTO PROJECT_ID.DATASET.mytable (_PARTITIONTIME, field1, field2) SELECT TIMESTAMP(“2017-05-01 21:30:00”), 1, “one”

分割テーブルへのデータの挿入

DML を使用して分割テーブルにデータを挿入することは、パーティショニングされていないテーブルにデータを挿入することと同じです。

たとえば、次の INSERT ステートメントでは、mytable2(パーティショニングされていないテーブル)からデータを選択して、分割テーブル mycolumntable に行を追加します。

INSERT INTO PROJECT_ID.DATASET.mycolumntable (ts, field1) SELECT ts, id from PROJECT_ID.DATASET.mytable2

データの削除

分割テーブルから行を削除するには、DML の DELETE ステートメントを使用します。

取り込み時間分割テーブルのデータの削除

次の DELETE ステートメントでは、2017 年 6 月 1 日のパーティション(“2017-06-01”)、または field121 に等しい mytable からすべての行を削除します。_PARTITIONTIME 疑似列を使用してパーティションを参照します。

DELETE PROJECT_ID.DATASET.mytable WHERE field1 = 21 AND _PARTITIONTIME = “2017-05-01”

分割テーブルのデータの削除

DML を使用して分割テーブルのデータを削除することは、パーティショニングされていないテーブルからデータを削除することと同じです。

たとえば、次の DELETE ステートメントでは、mycolumntable の 2017 年 6 月 1 日のパーティション(“2017-06-01”)から、field121 に等しいすべての行を削除します。

DELETE PROJECT_ID.DATASET.mycolumntable WHERE field1 = 21 AND DATE(ts) = “2017-05-01”

データの更新

分割テーブルの行を更新するには、UPDATE ステートメントを使用します。

取り込み時間分割テーブルのデータの更新

次の UPDATE ステートメントでは、あるパーティションから別のパーティションに行を移動します。field121 に等しい mytable の 2017 年 5 月 1 日のパーティション(“2017-05-01”)の行が、2017 年 6 月 1 日のパーティション(“2017-06-01”)に移動します。

UPDATE PROJECT_ID.DATASET.mytable SET _PARTITIONTIME = “2017-06-01”  WHERE _PARTITIONTIME = “2017-05-01” AND field1 = 21

分割テーブルのデータの更新

DML を使用して分割テーブルのデータを更新することは、パーティショニングされていないテーブルのデータを更新することと同じです。たとえば、次の UPDATE ステートメントでは、あるパーティションから別のパーティションに行を移動します。field121 に等しい mytable の 2017 年 5 月 1 日のパーティション(“2017-05-01”)の行が、2017 年 6 月 1 日のパーティション(“2017-06-01”)に移動します。

UPDATE PROJECT_ID.DATASET.mycolumntable SET ts = “2017-06-01”  WHERE DATE(ts) = “2017-05-01” AND field1 = 21

MERGE ステートメントの使用

DML の MERGE ステートメントを使用すると、分割テーブルに対する INSERTUPDATEDELETE オペレーションを 1 つのステートメントに結合してアトミックに実行できます。

MERGE ステートメント使用時のパーティションのプルーニング

分割テーブルに対して MERGE ステートメントを実行するとき、_PARTITIONTIME 疑似列を使用するか(取り込み時間分割テーブルの場合)、日付列またはタイムスタンプ列を使用することで(分割テーブルの場合)、ステートメントの対象とするパーティションを限定できます。パーティションをプルーニングすると、コストが節約され、クエリのパフォーマンスが向上します。

パーティションのプルーニング条件は、サブクエリ フィルタ、search_condition フィルタ、または merge_condition フィルタで指定できます。

以下の各例では、_PARTITIONTIME 擬似列を使用して取り込み時間分割テーブルを照会しています。

サブクエリを使用してソースデータをフィルタリングする

サブクエリでフィルタを使用してパーティションをプルーニングできます。たとえば、次の MERGE ステートメントは、ソーステーブルの '2018-01-01' パーティションにある行のみをスキャンします。

MERGE dataset.target T
USING (SELECT * FROM dataset.source WHERE _PARTITIONTIME = '2018-01-01') S
ON T.c1 = S.c1
WHEN MATCHED THEN
  DELETE

when_clausesearch_condition でフィルタを使用する

クエリ オプティマイザは、search_condition に指定されたフィルタを使用してパーティションをプルーニングしようとします。たとえば、次の MERGE ステートメントは、ターゲット テーブルの '2018-01-01''2018-01-02''2018-01-03' パーティションにある行のみをスキャンします。

MERGE dataset.target T
USING dataset.source S
ON T.c1 = S.c1
WHEN MATCHED AND T._PARTITIONTIME = '2018-01-01' THEN
  UPDATE SET c1 = S.c1
WHEN MATCHED AND T._PARTITIONTIME = '2018-01-02' THEN
  UPDATE SET c1 = c1 + 10
WHEN NOT MATCHED BY SOURCE AND T._PARTITIONTIME = '2018-01-03' THEN
  DELETE

次の例では、WHEN NOT MATCHED BY SOURCE 句に対してターゲット テーブル内のすべてのデータが必要となります。その結果、すべてのパーティションがスキャンされ、すべてのパーティションで読み取られたバイト数が課金されます。

MERGE dataset.target T
USING dataset.source S
ON T.c1 = S.c1
WHEN MATCHED AND T._PARTITIONTIME = '2018-01-01' THEN
  UPDATE SET c1 = S.c1
WHEN NOT MATCHED BY SOURCE THEN
  UPDATE SET c1 = c1 + 1

一般に、WHEN NOT MATCHED 句と WHEN NOT MATCHED BY SOURCE 句を組み合わせて使用すると、ソーステーブルとターゲット テーブルの FULL OUTER JOIN が行われます。通常、FULL OUTER JOIN でパーティションをプルーニングすることはできません。ただし、常時 false 述語を使用した場合、フィルタ条件をパーティションのプルーニングに使用できます。次のクエリでは、パーティション プルーニングを使用して、ターゲット テーブルとソーステーブルの両方でスキャン対象を '2018-01-01' パーティションのみに限定しています。

MERGE dataset.target T
USING dataset.source S
ON FALSE
WHEN NOT MATCHED AND _PARTITIONTIME = '2018-01-01' THEN
  INSERT(c1) VALUES(c1)
WHEN NOT MATCHED BY SOURCE AND _PARTITIONTIME = '2018-01-01' THEN
  DELETE

merge_condition でフィルタを使用する

クエリ オプティマイザは、merge_condition に指定されたフィルタを使用してパーティションをプルーニングしようとします。たとえば、次のクエリでは、ターゲット テーブルとソーステーブルの両方でスキャン対象を '2018-01-01' パーティションのみに限定しています。

MERGE dataset.target T
USING dataset.source S
ON T.c1 = S.c1 AND
  T._PARTITIONTIME = '2018-01-01' AND
  S._PARTITIONTIME = '2018-01-01'
WHEN MATCHED THEN
  UPDATE SET c1 = S.c1

この例では、merge_condition が、ソーステーブルとターゲット テーブルを結合する述語として使用されています。クエリ オプティマイザが述語プッシュダウンを使用できるかどうかは結合の種類によります。

次の MERGE ステートメントの例では、パーティションをプルーニングできません。その理由は、パーティション フィルタが、テーブルに直接適用できない結合条件の述語であるためです。

MERGE dataset.target T
USING dataset.source S
ON T.c1 = S.c1 AND T._PARTITIONTIME = '2018-01-01'
WHEN NOT MATCHED BY SOURCE THEN
  UPDATE SET c1 = S.c1

制限事項

DML の制限事項の詳細については、データ操作言語ページの制限事項をご覧ください。

割り当て

DML の割り当て情報については、割り当てと制限ページの DML ステートメントをご覧ください。

料金

DML の料金については、分割テーブルの DML の料金をご覧ください。

次のステップ

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

ご不明な点がありましたら、Google のサポートページをご覧ください。