sql >> Base de Datos >  >> RDS >> Sqlserver

Cómo agregar una columna de identidad a una tabla de base de datos existente que tiene una gran cantidad de filas

El proceso general probablemente será mucho más lento con más sobrecarga general de bloqueo, pero si solo le importa el tamaño del registro de transacciones, puede intentar lo siguiente.

  1. Agregue una columna de enteros que aceptan valores NULL sin identidad (solo cambio de metadatos).
  2. Escriba código para actualizar esto con enteros secuenciales únicos en lotes. Esto reducirá el tamaño de cada transacción individual y mantendrá el tamaño del registro bajo (suponiendo un modelo de recuperación simple). Mi código a continuación hace esto en lotes de 100. Es de esperar que tenga un PK existente que pueda aprovechar para continuar donde lo dejó en lugar de los escaneos repetidos que tomarán cada vez más tiempo hacia el final.
  3. use ALTER TABLE ... ALTER COLUMN para marcar la columna como NOT NULL . Esto requerirá que toda la tabla esté bloqueada y escaneada para validar el cambio, pero no requerirá mucho registro.
  4. Utilice ALTER TABLE ... SWITCH para hacer de la columna una columna de identidad. Este es un cambio de metadatos únicamente.

Código de ejemplo a continuación

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