Aggiornamento dei dati tabella partizionata mediante DML

Questa pagina fornisce una panoramica del supporto del data manipulation language (DML) per le tabelle partizionate.

Per ulteriori informazioni sui comandi DML, consulta:

Tabelle utilizzate negli esempi

Le seguenti definizioni dello schema JSON rappresentano le tabelle utilizzate negli esempi in questa pagina.

mytable: una tabella partizionata per data di importazione

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

mytable2: una tabella standard (non partizionata)

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

mycolumntable: una tabella partizionata partizionata utilizzando la colonna ts TIMESTAMP

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

Negli esempi in cui viene visualizzato COLUMN_ID, sostituiscilo con il nome della colonna su cui vuoi eseguire l'operazione.

Inserimento di dati

Utilizza un'istruzione INSERT DML per aggiungere righe a una tabella partizionata.

Inserimento di dati in tabelle partizionate per data di importazione

Quando utilizzi un'istruzione DML per aggiungere righe a una tabella partizionata per data di importazione, puoi specificare la partizione a cui devono essere aggiunte le righe. Fai riferimento alla partizione utilizzando la pseudocolonna _PARTITIONTIME.

Ad esempio, la seguente istruzione INSERT aggiunge una riga alla partizione del 1° maggio 2017 di mytable - “2017-05-01”.

INSERT INTO
  project_id.dataset.mytable (_PARTITIONTIME,
    field1,
    field2)
SELECT
  TIMESTAMP("2017-05-01"),
  1,
  "one"

È possibile utilizzare solo i timestamp corrispondenti a limiti di date esatti. Ad esempio, la seguente istruzione DML restituisce un errore:

INSERT INTO
  project_id.dataset.mytable (_PARTITIONTIME,
    field1,
    field2)
SELECT
  TIMESTAMP("2017-05-01 21:30:00"),
  1,
  "one"

Inserimento di dati in tabelle partizionate

L'inserimento di dati in una tabella partizionata utilizzando DML è uguale all'inserimento di dati in una tabella non partizionata.

Ad esempio, la seguente istruzione INSERT aggiunge righe alla tabella partizionata mycolumntable selezionando i dati da mytable2 (una tabella non partizionata).

INSERT INTO
  project_id.dataset.mycolumntable (ts,
    field1)
SELECT
  ts,
  id
FROM
  project_id.dataset.mytable2

Eliminazione di dati

Utilizza un'istruzione DELETE DML per eliminare righe da una tabella partizionata.

Eliminazione dei dati nelle tabelle partizionate per data di importazione

La seguente istruzione DELETE elimina tutte le righe della partizione ("2017-06-01") del 1° giugno 2017 di mytable in cui field1 è uguale a 21. Puoi fare riferimento alla partizione utilizzando la pseudocolonna _PARTITIONTIME.

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

Eliminazione dei dati nelle tabelle partizionate

L'eliminazione dei dati in una tabella partizionata utilizzando DML equivale all'eliminazione dei dati da una tabella non partizionata.

Ad esempio, la seguente istruzione DELETE elimina tutte le righe della partizione 1° giugno 2017 ("2017-06-01") di mycolumntable in cui field1 è uguale a 21.

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

Utilizzo di DML DELETE per eliminare le partizioni

Se un'istruzione DELETE idonea copre tutte le righe di una partizione, BigQuery rimuove l'intera partizione. Questa rimozione viene eseguita senza scansionare i byte o utilizzare gli slot. Il seguente esempio di un'istruzione DELETE copre l'intera partizione di un filtro sulla pseudocolonna _PARTITIONDATE:

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

Squalifiche comuni

Le query con le seguenti caratteristiche potrebbero non trarre vantaggio dall'ottimizzazione:

L'idoneità all'ottimizzazione può variare in base al tipo di partizionamento, ai metadati di archiviazione sottostanti e ai predicati dei filtri. Come best practice, esegui una prova simulata per verificare che la query non generi dati elaborati.

Transazione con più istruzioni

Questa ottimizzazione funziona all'interno di una transazione con più istruzioni. Il seguente esempio di query sostituisce una partizione con i dati di un'altra tabella in una singola transazione, senza eseguire la scansione della partizione per verificare la presenza dell'istruzione 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;

Aggiornamento dei dati

Utilizza un'istruzione UPDATE per aggiornare le righe di una tabella partizionata.

Aggiornamento dei dati nelle tabelle partizionate per data di importazione

La seguente istruzione UPDATE sposta le righe da una partizione all'altra. Le righe nella partizione del 1° maggio 2017 (“2017-05-01”) di mytable in cui field1 è uguale a 21 vengono spostate nella partizione del 1° giugno 2017 (“2017-06-01”).

UPDATE
  project_id.dataset.mytable
SET
  _PARTITIONTIME = "2017-06-01"
WHERE
  _PARTITIONTIME = "2017-05-01"
  AND field1 = 21

Aggiornamento dei dati nelle tabelle partizionate

L'aggiornamento dei dati in una tabella partizionata mediante DML è uguale all'aggiornamento dei dati da una tabella non partizionata. Ad esempio, la seguente UPDATE istruzione sposta le righe da una partizione all'altra. Le righe nella partizione del 1° maggio 2017 (“2017-05-01”) di mytable in cui field1 è uguale a 21 vengono spostate nella partizione del 1° giugno 2017 (“2017-06-01”).

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

DML in tabelle partizionate orarie, mensili e annuali

Puoi utilizzare le istruzioni DML per modificare una tabella partizionata oraria, mensile o annuale. Fornisci l'intervallo di ore, mesi o anni delle date/timestamp/date e ora pertinenti, come nel seguente esempio per le tabelle partizionate mensili:

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

Oppure un altro esempio per le tabelle partizionate con colonna 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");'

Utilizzo di un'istruzione MERGE

Utilizza un'istruzione MERGE DML per combinare le operazioni INSERT, UPDATE e DELETE per una tabella partizionata in un'istruzione ed eseguirle in modo atomico.

Potatura delle partizioni quando si utilizza un'istruzione MERGE

Quando esegui un'istruzione MERGE su una tabella partizionata, puoi limitare le partizioni sottoposte a scansione includendo la colonna di partizione in un filtro della sottoquery, in un filtro search_condition o in un filtro merge_condition. La potatura può verificarsi durante la scansione della tabella di origine o della tabella di destinazione o di entrambe.

Ciascuno degli esempi riportati di seguito esegue una query su una tabella partizionata per data di importazione utilizzando la pseudocolonna _PARTITIONTIME come filtro.

Utilizzo di una sottoquery per filtrare i dati di origine

Nel seguente statement MERGE, la sottoquery nella clausola USING filtra in base alla pseudocolonna _PARTITIONTIME nella tabella di origine.

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

Se esamini il piano di esecuzione della query, noterai che la sottoquery viene eseguita per prima. Vengono scansionate solo le righe della partizione '2018-01-01' nella tabella di origine. Ecco la fase pertinente nel piano di query:

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

Utilizzo di un filtro nel search_condition di un when_clause

Se un search_condition contiene un filtro, l'ottimizzatore delle query tenta di eliminare le partizioni. Ad esempio, nell'istruzione MERGE seguente, ogni clausola WHEN MATCHED e WHEN NOT MATCHED contiene un filtro sulla pseudocolonna _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

Durante la fase di unione, nella tabella di destinazione vengono analizzate solo le seguenti partizioni: '2018-01-01', '2018-01-02' e '2018-01-03', ovvero l'unione di tutti i filtri search_condition.

Dal piano di esecuzione della query:

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))

Tuttavia, nell'esempio seguente, la clausola WHEN NOT MATCHED BY SOURCE non ha un'espressione di filtro:

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

Questa query deve analizzare l'intera tabella di destinazione per calcolare la clausola WHEN NOT MATCHED BY SOURCE. Di conseguenza, nessuna partizione viene eliminata.

Utilizzo di un predicato falso costante in un merge_condition

Se utilizzi le clausole WHEN NOT MATCHED e WHEN NOT MATCHED BY SOURCE insieme, solitamente BigQuery esegue un join esterno completo, che non può essere eliminato. Tuttavia, se la condizione di unione utilizza un predicato costante falso, BigQuery può utilizzare la condizione di filtro per l'eliminazione delle partizioni. Per ulteriori informazioni sull'utilizzo di predicati di valore falso costante, consulta la descrizione della clausola merge_condition nella documentazione relativa all'istruzione MERGE.

L'esempio seguente esegue la scansione solo della partizione '2018-01-01' sia nelle tabelle di destinazione che in quelle di origine.

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

Utilizzare un filtro in un merge_condition

Lo strumento di ottimizzazione delle query tenta di utilizzare un filtro in un merge_condition per eliminare le partizioni. L'ottimizzatore delle query potrebbe o meno essere in grado di inviare il predicato all'istruzione di scansione della tabella, a seconda del tipo di join.

Nell'esempio seguente, merge_condition viene utilizzato come predicato per unire le tabelle di origine e di destinazione. Lo strumento di ottimizzazione delle query può spostare questo predicato verso il basso quando esegue la scansione di entrambe le tabelle. Di conseguenza, la query esegue la scansione solo della partizione '2018-01-01' nelle tabelle di destinazione e di origine.

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

Nell'esempio seguente, merge_condition non contiene un predicato per la tabella di origine, pertanto non è possibile eseguire l'eliminazione delle partizioni nella tabella di origine. L'istruzione contiene un predicato per la tabella di destinazione, ma utilizza una clausola WHEN NOT MATCHED BY SOURCE anziché una clausola WHEN MATCHED. Ciò significa che la query deve scansionare l'intera tabella di destinazione per trovare le righe che non corrispondono.

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

Limitazioni

Per informazioni sulle limitazioni DML, consulta Limitazioni nella pagina Documentazione di riferimento DML.

Quote

Per informazioni sulle quote DML, consulta Istruzioni DML nella pagina Quote e limiti.

Prezzi

Per informazioni sui prezzi di DML, consulta Prezzi DML per le tabelle partizionate.

Sicurezza delle tabelle

Per controllare l'accesso alle tabelle in BigQuery, consulta Introduzione ai controlli di accesso alle tabelle.

Passaggi successivi