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

Come aggiungere una colonna di identità a una tabella di database esistente con un numero elevato di righe

Il processo complessivo sarà probabilmente molto più lento con un sovraccarico complessivo di blocco maggiore, ma se ti interessa solo la dimensione del registro delle transazioni, potresti provare quanto segue.

  1. Aggiungi una colonna intera non identità nullable (modifica solo dei metadati).
  2. Scrivi il codice per aggiornarlo con interi sequenziali univoci in batch. Ciò ridurrà le dimensioni di ogni singola transazione e manterrà le dimensioni del registro ridotte (supponendo un modello di ripristino semplice). Il mio codice di seguito lo fa in lotti di 100, si spera che tu abbia un PK esistente che puoi sfruttare per riprendere da dove eri rimasto piuttosto che le scansioni ripetute che richiederanno sempre più tempo verso la fine.
  3. usa ALTER TABLE ... ALTER COLUMN per contrassegnare la colonna come NOT NULL . Ciò richiederà il blocco e la scansione dell'intera tabella per convalidare la modifica, ma non richiederà molta registrazione.
  4. Usa ALTER TABLE ... SWITCH per rendere la colonna una colonna di identità. Questa è una modifica solo ai metadati.

Esempio di codice sotto

/*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 ;