Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Il modo più veloce per aggiornare 120 milioni di record

L'unico modo corretto per aggiornare una tabella di 120 milioni di record è con un SELECT istruzione che popola un secondo tavolo. Devi fare attenzione quando lo fai. Istruzioni di seguito.

Caso semplice

Per una tabella senza un indice cluster, durante un periodo senza DML simultaneo:

  • SELECT *, new_col = 1 INTO clone.BaseTable FROM dbo.BaseTable
  • ricrea indici, vincoli, ecc. su una nuova tabella
  • cambia vecchio e nuovo con ALTER SCHEMA ... TRANSFER.
  • elimina la vecchia tabella

Se non riesci a creare uno schema clone, lo farà un nome di tabella diverso nello stesso schema. Ricorda di rinominare tutti i tuoi vincoli e attivatori (se applicabile) dopo il passaggio.

Caso non semplice

Per prima cosa, ricrea la tua BaseTable con lo stesso nome in uno schema diverso, ad esempio clone.BaseTable . L'utilizzo di uno schema separato semplificherà il processo di ridenominazione in seguito.

  • Includi l'indice cluster , se applicabile. Ricorda che le chiavi primarie e i vincoli univoci possono essere raggruppati, ma non necessariamente.
  • Includi colonne identità e colonne calcolate , se applicabile.
  • Includi la tua nuova colonna INT , ovunque appartenga.
  • Non includere uno dei seguenti:
    • trigger
    • vincoli chiave straniera
    • indici non cluster/chiavi primarie/vincoli univoci
    • controlla i vincoli o i vincoli predefiniti. Le impostazioni predefinite non fanno molta differenza, ma stiamo cercando di mantenere le cose minime.

Quindi, testa il tuo inserto con 1000 righe:

-- assuming an IDENTITY column in BaseTable
SET IDENTITY_INSERT clone.BaseTable ON
GO
INSERT clone.BaseTable WITH (TABLOCK) (Col1, Col2, Col3)
SELECT TOP 1000 Col1, Col2, Col3 = -1
FROM dbo.BaseTable
GO
SET IDENTITY_INSERT clone.BaseTable OFF

Esamina i risultati. Se tutto appare in ordine:

  • tronca la tabella dei cloni
  • Assicurati che il database sia registrato in blocco o con un modello di ripristino semplice
  • esegui l'inserimento completo.

Ci vorrà del tempo, ma non quanto un aggiornamento. Una volta completato, controlla i dati nella tabella dei cloni per assicurarti che tutto sia corretto.

Quindi, ricrea tutte le chiavi primarie non raggruppate/vincoli univoci/indici e vincoli di chiave esterna (in quest'ordine). Ricrea l'impostazione predefinita e controlla i vincoli, se applicabili. Ricrea tutti i trigger. Ricrea ogni vincolo, indice o trigger in un batch separato. es:

ALTER TABLE clone.BaseTable ADD CONSTRAINT UQ_BaseTable UNIQUE (Col2)
GO
-- next constraint/index/trigger definition here

Infine, sposta dbo.BaseTable in uno schema di backup e clone.BaseTable allo schema dbo (o ovunque la tua tabella dovrebbe vivere).

-- -- perform first true-up operation here, if necessary
-- EXEC clone.BaseTable_TrueUp
-- GO
-- -- create a backup schema, if necessary
-- CREATE SCHEMA backup_20100914
-- GO
BEGIN TRY
  BEGIN TRANSACTION
  ALTER SCHEMA backup_20100914 TRANSFER dbo.BaseTable
  -- -- perform second true-up operation here, if necessary
  -- EXEC clone.BaseTable_TrueUp
  ALTER SCHEMA dbo TRANSFER clone.BaseTable
  COMMIT TRANSACTION
END TRY
BEGIN CATCH
  SELECT ERROR_MESSAGE() -- add more info here if necessary
  ROLLBACK TRANSACTION
END CATCH
GO

Se hai bisogno di liberare spazio su disco, potresti eliminare la tabella originale in questo momento, anche se potrebbe essere prudente conservarla per un po' più a lungo.

Inutile dire che questo è idealmente un offline operazione. Se ci sono persone che modificano i dati mentre esegui questa operazione, dovrai eseguire un'operazione di allineamento con l'opzione dello schema. Consiglio di creare un trigger su dbo.BaseTable per registrare tutto il DML in una tabella separata. Abilita questo trigger prima di iniziare l'inserimento. Quindi, nella stessa transazione in cui esegui il trasferimento dello schema, utilizza la tabella di registro per eseguire un true-up. Testalo prima su un sottoinsieme di dati! I delta sono facili da rovinare.