2011-08-23 15 views
6

Tengo una tabla de base de datos que tiene ~ 40 000 000 filas. Quiero agregar una columna de identidad a esta tabla. ¿Cómo hacerlo de una manera amigable con los registros?Cómo agregar una columna de identidad a una tabla de base de datos existente que tiene un gran número de filas

Cuando hago lo siguiente:

ALTER TABLE table_1 
    ADD id INT IDENTITY 

esto sólo se llena todo el espacio de registro.

¿Hay alguna forma de hacerlo de forma compatible con los registros? La base de datos está en SQL Server 2008.

Gracias, Mohan.

+2

¿Este es MySQL, SQL Server, PostGres, Oracle? – JNK

+7

deshabilitar el registro, agregar columna, habilitar el registro. –

+0

¿No debería ser eso una respuesta y no solo un comentario? –

Respuesta

4

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

  1. Agregue una columna de nulidad de entero entero (los metadatos solo cambian).
  2. Escriba el 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 de registro bajo (suponiendo un modelo de recuperación simple). Mi código a continuación hace esto en lotes de 100 con suerte usted tiene un PK existente que puede aprovechar para continuar donde lo dejó en lugar de los escaneos repetidos que tomarán cada vez más hacia el final.
  3. use ALTER TABLE ... ALTER COLUMN para marcar la columna como NOT NULL. Esto requerirá que toda la tabla se bloquee y escanee para validar el cambio pero no requiera mucho registro.
  4. Use ALTER TABLE ... SWITCH para hacer que la columna sea una columna de identidad. Este es un cambio solo de metadatos.

ejemplo de código siguiente

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

¿Tiene un marco de tiempo en el que puede poner la base de datos en el modo de usuario único? Lo mejor es hacer esto en prod en modo de usuario único y con todos los usuarios excepto el dba bloqueado. – HLGEM

1

que acabo de hacer esto a mi tabla que tiene más de 2700 filas. Vaya al diseño de la tabla, agregue la nueva columna, configúrelo para que no permita valores nulos, establezca la columna como una columna de identidad en las propiedades de la columna, y eso debería hacerlo. Literalmente hice esto hace menos de 5 minutos y funcionó para mí. Seleccione como respuesta si esto responde su pregunta.

Cuestiones relacionadas