使用 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"}
    ]

在出現 COLUMN_ID 的範例中,請將其替換為要操作的資料欄名稱。

插入資料

使用 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 陳述式會刪除 mytable 的 2017 年 6 月 1 日分區 ("2017-06-01") 中,field1 等於21 的所有資料列。您可以使用 _PARTITIONTIME 虛擬資料欄來參照分區。

DELETE
  project_id.dataset.mytable
WHERE
  field1 = 21
  AND _PARTITIONTIME = "2017-06-01"

刪除分區資料表中的資料

使用 DML 從分區資料表中刪除資料的程序,與從非分區資料表中刪除資料的程序相同。

舉例來說,下列 DELETE 陳述式會刪除 mycolumntable 的 2017 年 6 月 1 日分區 ("2017-06-01") 中,field1 等於 21 的所有資料列。

DELETE
  project_id.dataset.mycolumntable
WHERE
  field1 = 21
  AND DATE(ts) = "2017-06-01"

使用 DML DELETE 刪除分區

如果符合條件的 DELETE 陳述式涵蓋分區中的所有資料列,BigQuery 就會移除整個分區。這項移除作業不會掃描位元組或耗用插槽。以下 DELETE 陳述式的範例涵蓋 _PARTITIONDATE 虛擬欄上的篩選器的整個分區:

DELETE mydataset.mytable
WHERE _PARTITIONDATE IN ('2076-10-07', '2076-03-06');

常見的違規失格原因

以下查詢可能無法從最佳化中受益:

最佳化功能的使用資格可能因分區類型、基礎儲存空間中繼資料和篩選器述詞而異。最佳做法是執行模擬執行,確認查詢結果的處理大小為 0 位元組。

多陳述式交易

這項最佳化功能適用於多陳述式交易。以下查詢範例會在單一交易中,將分區替換為其他資料表中的資料,而不會掃描 DELETE 陳述式的分區。

DECLARE REPLACE_DAY DATE;
BEGIN TRANSACTION;

-- find the partition which we want to replace
SET REPLACE_DAY = (SELECT MAX(d) FROM mydataset.mytable_staging);

-- delete the entire partition from mytable
DELETE FROM mydataset.mytable WHERE part_col = REPLACE_DAY;

-- insert the new data into the same partition in mytable
INSERT INTO mydataset.mytable
SELECT * FROM mydataset.mytable_staging WHERE part_col = REPLACE_DAY;

COMMIT TRANSACTION;

更新資料

請使用 UPDATE 陳述式來更新分區資料表中的資料列。

更新擷取時間分區資料表中的資料

以下 UPDATE 陳述式會將資料列從一個分區移至另一個分區。mytable 的 2017 年 5 月 1 日分區 (“2017-05-01”) 中,field1 等於 21 的所有資料列都會移至 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 陳述式會將資料列從一個分區移至另一個分區。mytable 的 2017 年 5 月 1 日分區 (“2017-05-01”) 中,field1 等於 21 的所有資料列都會移至 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

在每小時、每月和每年分區資料表中使用 DML

您可以使用 DML 陳述式修改每小時、每月或每年的分區資料表。提供相關日期/時間戳記/日期時間的時間範圍 (小時、月或年),如以下每月分區資料表的範例所示:

    bq query --nouse_legacy_sql 'DELETE FROM my_dataset.my_table WHERE
    TIMESTAMP_TRUNC(ts_column, MONTH) = "2020-01-01 00:00:00";'

以下是另一個分區資料表 (含 DATETIME 欄) 的範例:

    bq query --nouse_legacy_sql 'DELETE FROM my_dataset.my_table WHERE
    dt_column BETWEEN DATETIME("2020-01-01")
    AND DATETIME("2020-05-01");'

使用 MERGE 陳述式

您可以使用 DML MERGE 陳述式,將分區資料表的 INSERTUPDATEDELETE 作業合併成單一陳述式,並以不可分割的形式予以執行。

在使用 MERGE 陳述式時縮減分區

對分區資料表執行 MERGE 陳述式時,您可以在子查詢篩選器、search_condition 篩選器或 merge_condition 篩選器中加入分區資料欄,藉此限制要掃描的分區。掃描來源資料表或目標資料表時,可能會發生修剪。

以下每個範例均使用 _PARTITIONTIME 虛擬資料欄做為篩選器,查詢擷取時間分區資料表。

使用子查詢篩選來源資料

在下列 MERGE 陳述式中,USING 子句中的子查詢會根據來源資料表中的 _PARTITIONTIME 虛擬欄篩選資料。

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

查看查詢執行計畫,會發現子查詢會先執行。系統只會掃描來源資料表中 '2018-01-01' 分區的資料列。以下是查詢計畫中的相關階段:

READ $10:name, $11:_PARTITIONTIME
FROM temp.source
WHERE equal($11, 1514764800.000000000)

when_clausesearch_condition 中使用篩選器

如果 search_condition 包含篩選器,查詢最佳化工具就會嘗試縮減分區。例如,在以下 MERGE 陳述式中,每個 WHEN MATCHEDWHEN NOT MATCHED 子句都包含 _PARTITIONTIME 虛擬欄的篩選器。

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

在彙整階段,系統只會掃描目標資料表中的以下分區:'2018-01-01''2018-01-02''2018-01-03',也就是所有 search_condition 篩選條件的聯集。

查詢執行計畫:

READ
$1:COLUMN_ID, $2:_PARTITIONTIME, $3:$file_temp_id, $4:$row_temp_id
FROM temp.target
WHERE or(equal($2, 1514764800.000000000), equal($2, 1514851200.000000000), equal($2, 1514937600.000000000))

不過,在下列範例中,WHEN NOT MATCHED BY SOURCE 子句並未包含篩選器運算式:

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

這項查詢必須掃描整個目標資料表,才能計算 WHEN NOT MATCHED BY SOURCE 子句。因此,系統不會修剪任何分區。

merge_condition 中使用常數 false 預設詞

如果同時使用 WHEN NOT MATCHEDWHEN NOT MATCHED BY SOURCE 子句,BigQuery 通常會執行完整外部聯結,而這類聯結無法修剪。不過,如果合併條件使用常數假述詞,BigQuery 就能使用篩選條件來縮減分區。如要進一步瞭解如何使用常數為假的判定式,請參閱 MERGE 陳述式說明文件中的 merge_condition 子句說明。

以下範例只會掃描目標和來源資料表中的 '2018-01-01' 分區。

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

merge_condition 中使用篩選器

查詢最佳化工具會嘗試在 merge_condition 中使用篩選器來縮減分區。查詢最佳化工具不一定能將述詞下推至資料表掃描階段,這取決於彙整類型。

在以下範例中,merge_condition 做為彙整來源和目標資料表的述詞。查詢最佳化工具可在掃描兩個資料表時,將這個述詞下推。因此,查詢只會掃描目標和來源資料表中的 '2018-01-01' 分區。

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

在下一個範例中,merge_condition 不包含來源資料表的述詞,因此無法對來源資料表執行分區裁剪。陳述式確實包含目標資料表的述詞,但使用 WHEN NOT MATCHED BY SOURCE 子句,而非 WHEN MATCHED 子句。也就是說,查詢必須掃描整個目標資料表,找出不相符的資料列。

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

限制

如要瞭解 DML 的限制,請參閱 DML 參考資料頁面上的「限制」一節。

配額

如要瞭解 DML 配額資訊,請參閱「配額與限制」頁面上的 DML 陳述式

定價

如要瞭解 DML 定價,請參閱分區資料表的 DML 定價

表格安全性

如要控管 BigQuery 中資料表的存取權,請參閱「使用 IAM 控管資源存取權」。

後續步驟