Daten aus partitionierten Tabellen mithilfe von DML aktualisieren
Diese Seite bietet eine Übersicht über die Unterstützung der Datenbearbeitungssprache (Data Manipulation Language, DML) für partitionierte Tabellen.
Weitere Informationen zu DML finden Sie unter:
In Beispielen verwendete Tabellen
Die folgenden JSON-Schemadefinitionen stellen die Tabellen dar, die in den Beispielen auf dieser Seite verwendet werden.
mytable
: eine nach Aufnahmezeit partitionierte Tabelle
[ {"name": "field1", "type": "INTEGER"}, {"name": "field2", "type": "STRING"} ]
mytable2
: eine Standardtabelle (nicht partitioniert)
[ {"name": "id", "type": "INTEGER"}, {"name": "ts", "type": "TIMESTAMP"} ]
mycolumntable
: eine nach der Spalte ts
TIMESTAMP
partitionierte Tabelle
[ {"name": "field1", "type": "INTEGER"}, {"name": "field2", "type": "STRING"} {"name": "field3", "type": "BOOLEAN"} {"name": "ts", "type": "TIMESTAMP"} ]
Ersetzen Sie in Beispielen, in denen COLUMN_ID erscheint, die ID durch den Namen der Spalte, die Sie bearbeiten möchten.
Daten einfügen
Mit der DML-Anweisung INSERT
können Sie einer partitionierten Tabelle Zeilen hinzufügen.
Daten in nach Aufnahmezeit partitionierte Tabellen einfügen
Wenn Sie einer nach Aufnahmezeit partitionierten Tabelle Zeilen mithilfe einer DML-Anweisung hinzufügen möchten, können Sie die Partition festlegen, der die Zeilen hinzugefügt werden sollen. Mit der Pseudospalte _PARTITIONTIME
verweisen Sie auf die Partition.
Durch die folgende INSERT
-Anweisung wird beispielsweise der Partition von mytable
vom 1. Mai 2017, “2017-05-01”
, eine Zeile hinzugefügt.
INSERT INTO project_id.dataset.mytable (_PARTITIONTIME, field1, field2) SELECT TIMESTAMP("2017-05-01"), 1, "one"
Es können nur Zeitstempel verwendet werden, die den genauen Datumsgrenzen entsprechen. Bei der folgenden DML-Anweisung wird beispielsweise ein Fehler zurückgegeben:
INSERT INTO project_id.dataset.mytable (_PARTITIONTIME, field1, field2) SELECT TIMESTAMP("2017-05-01 21:30:00"), 1, "one"
Daten in partitionierte Tabellen einfügen
Das Einfügen von Daten in eine partitionierte Tabelle mithilfe von DML erfolgt auf die gleiche Weise wie das Einfügen von Daten in eine nicht partitionierte Tabelle.
Durch die folgende INSERT
-Anweisung werden Zeilen zur partitionierten Tabelle mycolumntable
hinzugefügt, indem Daten aus mytable2
(einer nicht partitionierten Tabelle) ausgewählt werden.
INSERT INTO project_id.dataset.mycolumntable (ts, field1) SELECT ts, id FROM project_id.dataset.mytable2
Daten löschen
Mit einer DELETE
-DML-Anweisung können Sie Zeilen aus einer partitionierten Tabelle löschen.
Daten in nach Aufnahmezeit partitionierten Tabellen löschen
Mit der folgenden DELETE
-Anweisung werden alle Zeilen aus der Partition vom 1. Juni 2017 ("2017-06-01"
) von mytable
gelöscht, wobei field1
gleich 21
ist. Mit der Pseudospalte _PARTITIONTIME
verweisen Sie auf die Partition.
DELETE project_id.dataset.mytable WHERE field1 = 21 AND _PARTITIONTIME = "2017-06-01"
Daten in partitionierten Tabellen löschen
Das Löschen von Daten in einer partitionierten Tabelle mithilfe von DML erfolgt auf die gleiche Weise wie das Löschen von Daten aus einer nicht partitionierten Tabelle.
Mit der folgenden DELETE
-Anweisung werden beispielsweise alle Zeilen aus der Partition vom 1. Juni 2017 ("2017-06-01"
) von mycolumntable
gelöscht, wobei field1
gleich 21
ist.
DELETE project_id.dataset.mycolumntable WHERE field1 = 21 AND DATE(ts) = "2017-06-01"
Partitionen mit DML DELETE löschen
Wenn eine qualifizierende DELETE
-Anweisung alle Zeilen in einer Partition abdeckt, entfernt BigQuery die gesamte Partition. Das Entfernen erfolgt, ohne Byte zu scannen oder Slots zu verbrauchen. Im folgenden Beispiel einer DELETE
-Anweisung wird die gesamte Partition eines Filters in der Pseudospalte _PARTITIONDATE
abgedeckt:
DELETE mydataset.mytable WHERE _PARTITIONDATE IN ('2076-10-07', '2076-03-06');
Häufige Disqualifikationen
Abfragen mit den folgenden Merkmalen profitieren möglicherweise nicht von der Optimierung:
- Teilweise Partitionsabdeckung
- Verweise auf nicht partitionierte Spalten
- Zuletzt aufgenommene Daten über die Storage Write API von BigQuery oder die Legacy-Streaming API
- Filter mit Unterabfragen oder nicht unterstützten Prädikaten
Die Eignung einer Optimierung kann je nach Art der Partitionierung, den zugrunde liegenden Speichermetadaten und den Filterprädikaten variieren. Als Best Practice führen Sie einen Probelauf durch, um zu prüfen, ob für die Abfrage 0 Byte verarbeitet werden.
Transaktion mit mehreren Anweisungen
Diese Optimierung funktioniert in einer Transaktion mit mehreren Anweisungen. Im folgenden Abfragebeispiel wird eine Partition durch Daten aus einer anderen Tabelle in einer einzelnen Transaktion ersetzt, ohne die Partition nach der Anweisung DELETE
zu scannen.
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;
Daten aktualisieren
Mit einer UPDATE
-Anweisung können Sie Zeilen in einer partitionierten Tabelle aktualisieren.
Daten in nach Aufnahmezeit partitionierten Tabellen aktualisieren
Durch die folgende UPDATE
-Anweisung werden Zeilen zwischen Partitionen verschoben.
Zeilen in der Partition vom 1. Mai 2017 (“2017-05-01”
) von mytable
, bei denen field1
gleich 21
ist, werden in die Partition vom 1. Juni 2017 (“2017-06-01”
) verschoben.
UPDATE project_id.dataset.mytable SET _PARTITIONTIME = "2017-06-01" WHERE _PARTITIONTIME = "2017-05-01" AND field1 = 21
Daten in partitionierten Tabellen aktualisieren
Das Aktualisieren von Daten in einer partitionierten Tabelle mithilfe von DML erfolgt auf die gleiche Weise wie das Aktualisieren von Daten in einer nicht partitionierten Tabelle. Mit der folgenden UPDATE
-Anweisung werden beispielsweise Zeilen zwischen Partitionen verschoben. Zeilen in der Partition vom 1. Mai 2017 (“2017-05-01”
) von mytable
, bei denen field1
gleich 21
ist, werden in die Partition vom 1. Juni 2017 (“2017-06-01”
) verschoben.
UPDATE project_id.dataset.mycolumntable SET ts = "2017-06-01" WHERE DATE(ts) = "2017-05-01" AND field1 = 21
DML in stündlich, monatlich und jährlich partitionierten Tabellen
Mit DML-Anweisungen können Sie eine stündlich, monatlich oder jährlich partitionierte Tabelle ändern. Geben Sie die Stunde, den Monat oder das Jahr des entsprechenden Datums/Zeitstempels/Datums-/Uhrzeitformats an, wie im folgenden Beispiel für monatlich partitionierte Tabellen gezeigt:
bq query --nouse_legacy_sql 'DELETE FROM my_dataset.my_table WHERE TIMESTAMP_TRUNC(ts_column, MONTH) = "2020-01-01 00:00:00";'
Oder ein anderes Beispiel für partitionierte Tabellen mit der Spalte 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
-Anweisung verwenden
Mit einer MERGE
-DML-Anweisung können Sie die Vorgänge INSERT
, UPDATE
und DELETE
für eine partitionierte Tabelle in einer Anweisung zusammenfassen und so gemeinsam ausführen.
Partitionen bei Verwendung einer MERGE
-Anweisung bereinigen
Wenn Sie eine MERGE
-Anweisung für eine partitionierte Tabelle ausführen, können Sie begrenzen, welche Partitionen gescannt werden. Fügen Sie dazu die Partitionierungsspalte in einen Unterabfragefilter, einen search_condition
-Filter oder einen merge_condition
-Filter ein.
Das Bereinigen kann beim Scannen der Quelltabelle oder der Zieltabelle oder von beidem auftreten.
In jedem der folgenden Beispiele wird eine nach Aufnahmezeit partitionierte Tabelle mithilfe der Pseudospalte _PARTITIONTIME
als Filter abgefragt.
Quelldaten mithilfe einer Unterabfrage filtern
In der folgenden MERGE
-Anweisung filtert die Unterabfrage in der USING
-Klausel nach der Pseudospalte _PARTITIONTIME
in der Quelltabelle.
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
Die Unterabfrage wird dann gemäß dem Abfrageausführungsplan zuerst ausgeführt. Nur die Zeilen in der Partition '2018-01-01'
in der Quelltabelle werden gescannt. Hier ist die relevante Phase im Abfrageplan:
READ $10:name, $11:_PARTITIONTIME
FROM temp.source
WHERE equal($11, 1514764800.000000000)
Filter in der search_condition
einer when_clause
verwenden
Wenn eine search_condition
einen Filter enthält, versucht die Abfrageoptimierung, Partitionen zu bereinigen. In der folgenden MERGE
-Anweisung enthält beispielsweise jede WHEN
MATCHED
- und WHEN NOT MATCHED
-Klausel einen Filter für die Pseudospalte _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
Während der Join-Phase werden nur die folgenden Partitionen in der Zieltabelle gescannt: '2018-01-01'
, '2018-01-02'
und '2018-01-03'
, also die Union aller search_condition
-Filter.
Gehen Sie im Abfrageausführungsplan so vor:
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))
Im folgenden Beispiel hat die WHEN NOT MATCHED BY SOURCE
-Klausel jedoch keinen Filterausdruck:
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
Diese Abfrage muss die gesamte Zieltabelle scannen, um die WHEN NOT MATCHED BY
SOURCE
-Klausel zu berechnen. Daher werden keine Partitionen bereinigt.
Konstantes falsches Prädikat in einer merge_condition
verwenden
Wenn Sie die Klauseln WHEN NOT MATCHED
und WHEN NOT MATCHED BY SOURCE
zusammen verwenden, führt BigQuery normalerweise einen vollständigen äußeren Join aus, der nicht bereinigt werden kann. Wenn die Zusammenführungsbedingung jedoch ein konstantes falsches Prädikat verwendet, kann BigQuery die Filterbedingung für die Partitionsbereinigung nutzen. Weitere Informationen zur Verwendung konstanter falscher Prädikate finden Sie in der Beschreibung der merge_condition
-Klausel in der Dokumentation zur MERGE
-Anweisung.
Im folgenden Beispiel wird nur die Partition '2018-01-01'
in der Ziel- und der Quelltabelle gescannt.
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
Filter in einer merge_condition
verwenden
Die Abfrageoptimierung versucht, Partitionen mithilfe eines Filters in einer merge_condition
zu bereinigen. Die Abfrageoptimierung ist vielleicht in der Lage, das Prädikat je nach Join-Typ nach unten in die Tabellenscan-Phase zu verschieben.
Im folgenden Beispiel wird die merge_condition
als Prädikat verwendet, um die Quell- und die Zieltabelle zu verbinden. Die Abfrageoptimierung kann dieses Prädikat nach unten verschieben, wenn beide Tabellen gescannt werden. Daher scannt die Abfrage nur die Partition '2018-01-01'
in der Ziel- und der Quelltabelle.
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
Im nächsten Beispiel enthält die merge_condition
kein Prädikat für die Quelltabelle. Daher kann keine Partitionsbereinigung für die Quelltabelle durchgeführt werden. Die Anweisung enthält ein Prädikat für die Zieltabelle, aber die Anweisung verwendet eine WHEN NOT MATCHED BY SOURCE
-Klausel statt einer WHEN MATCHED
-Klausel. Das bedeutet, dass die Abfrage die gesamte Zieltabelle nach den nicht übereinstimmenden Zeilen scannen muss.
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
Beschränkungen
Informationen zu DML-Beschränkungen finden Sie unter Beschränkungen in der DML-Referenz.
Kontingente
Informationen zu DML-Kontingenten erhalten Sie auf der Seite Kontingente und Limits unter DML-Anweisungen.
Preise
Informationen zu DML-Preisen finden Sie unter DML-Preise für partitionierte Tabellen.
Tabellensicherheit
Informationen zum Steuern des Zugriffs auf Tabellen in BigQuery finden Sie unter Einführung in die Tabellenzugriffssteuerung.
Nächste Schritte
- Partitionierte Tabellen erstellen
- Partitionierte Tabellen abfragen
- Einführung in DML
- DML-Anweisungen mithilfe der DML-Syntax erstellen