2011-08-23 17 views
6

Ho una tabella di database che ha ~ 40 000 000 righe. Voglio aggiungere una colonna Identity a questa tabella. Come farlo in un modo log-friendly?Come aggiungere una colonna Identity a una tabella di database esistente che ha un numero elevato di righe

Quando faccio la seguente:

ALTER TABLE table_1 
    ADD id INT IDENTITY 

questo riempie solo l'intero spazio di log.

C'è un modo per farlo in modo log-friendly? Il database è su SQL Server 2008.

Grazie, Mohan.

+2

È questo MySQL, SQL Server, PostGres, Oracle? – JNK

+7

disattiva registro, aggiungi colonna, attiva registro. –

+0

Non dovrebbe essere una risposta e non solo un commento? –

risposta

4

Il processo complessivo sarà probabilmente molto più lento con un sovraccarico complessivo di blocco generale, ma se ti interessa solo le dimensioni del registro delle transazioni puoi provare quanto segue.

  1. Aggiungere una colonna non identificata di valori non validi (modifica solo metadati).
  2. Scrive il codice per aggiornarlo con numeri interi sequenziali univoci in lotti. Ciò ridurrà le dimensioni di ogni singola transazione e manterrà le dimensioni del registro (presupponendo un modello di recupero semplice). Il mio codice qui sotto fa questo in lotti di 100, si spera che tu abbia un PK esistente che puoi sfruttare per riprendere da dove hai interrotto piuttosto che le scansioni ripetute che impiegheranno sempre più a lungo verso la fine.
  3. utilizzare ALTER TABLE ... ALTER COLUMN per contrassegnare la colonna come NOT NULL. Ciò richiederà che l'intera tabella sia bloccata e scansionata per convalidare la modifica ma non richiede molta registrazione.
  4. Utilizzare ALTER TABLE ... SWITCH per rendere la colonna una colonna di identità. Questo è un cambiamento dei metadati.

Esempio di codice Di seguito

/*Set up test table with just one column*/ 

CREATE TABLE table_1 (original_column INT) 
INSERT INTO table_1 
     SELECT DISTINCT 
       number 
     FROM master..spt_values 



/*Step 1 */ 
ALTER TABLE table_1 ADD id INT NULL 



/*Step 2 */ 
DECLARE @Counter INT = 0 , 
    @PrevCounter INT = -1 

WHILE @PrevCounter <> @Counter 
    BEGIN 
     SET @PrevCounter = @Counter; 
     WITH T AS (SELECT TOP 100 
           * , 
           ROW_NUMBER() OVER (ORDER BY @@SPID) 
           + @Counter AS new_id 
         FROM  table_1 
         WHERE id IS NULL 
        ) 
      UPDATE T 
      SET  id = new_id 
     SET @Counter = @Counter + @@ROWCOUNT 
    END 


BEGIN TRY; 
    BEGIN TRANSACTION ; 
    /*Step 3 */ 
    ALTER TABLE table_1 ALTER COLUMN id INT NOT NULL 

    /*Step 4 */ 
    DECLARE @TableScript NVARCHAR(MAX) = ' 
    CREATE TABLE dbo.Destination(
     original_column INT, 
     id INT IDENTITY(' + CAST(@Counter + 1 AS VARCHAR) + ',1) 
     ) 

     ALTER TABLE dbo.table_1 SWITCH TO dbo.Destination; 
    '  

    EXEC(@TableScript) 


    DROP TABLE table_1 ; 

    EXECUTE sp_rename N'dbo.Destination', N'table_1', 'OBJECT' ; 


    COMMIT TRANSACTION ; 
END TRY 
BEGIN CATCH 
    IF XACT_STATE() <> 0 
     ROLLBACK TRANSACTION ; 
    PRINT ERROR_MESSAGE() ; 
END CATCH ; 
+0

Hai un lasso di tempo in cui puoi inserire dataqbase in modalità utente singolo? È meglio farlo su prod in modalità utente singolo e con tutti gli utenti tranne il dba bloccato. – HLGEM

1

Ho appena fatto questo al mio tabella che ha più di 2700 righe. Vai al design della tabella, aggiungi la nuova colonna, impostala per non consentire i null, imposta la colonna come colonna di identità nelle proprietà della colonna e dovrebbe farlo. L'ho fatto solo meno di 5 minuti fa e ha funzionato per me. Si prega di selezionare come risposta se questo risponde alla tua domanda.

Problemi correlati