Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Comment ajouter une colonne d'identité à une table de base de données existante qui comporte un grand nombre de lignes

Le processus global sera probablement beaucoup plus lent avec une surcharge de verrouillage globale plus importante, mais si vous ne vous souciez que de la taille du journal des transactions, vous pouvez essayer ce qui suit.

  1. Ajouter une colonne non identitaire d'entier nullable (seules les métadonnées changent).
  2. Écrivez du code pour le mettre à jour avec des entiers séquentiels uniques par lots. Cela réduira la taille de chaque transaction individuelle et réduira la taille du journal (en supposant un modèle de récupération simple). Mon code ci-dessous le fait par lots de 100, j'espère que vous avez un PK existant que vous pouvez utiliser pour reprendre là où vous vous êtes arrêté plutôt que les analyses répétées qui prendront de plus en plus de temps vers la fin.
  3. utiliser ALTER TABLE ... ALTER COLUMN pour marquer la colonne comme NOT NULL . Cela nécessitera que la table entière soit verrouillée et analysée pour valider la modification, mais ne nécessitera pas beaucoup de journalisation.
  4. Utilisez ALTER TABLE ... SWITCH pour faire de la colonne une colonne d'identité. Il s'agit d'un changement de métadonnées uniquement.

Exemple de code ci-dessous

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