sql >> Databasteknik >  >> RDS >> Sqlserver

Hur man lägger till en identitetskolumn till en befintlig databastabell som har ett stort antal rader

Den övergripande processen kommer förmodligen att vara mycket långsammare med mer övergripande låsning, men om du bara bryr dig om storleken på transaktionsloggen kan du prova följande.

  1. Lägg till en nollbar heltalskolumn utan identitet (endast metadata ändras).
  2. Skriv kod för att uppdatera detta med unika sekventiella heltal i batcher. Detta kommer att minska storleken på varje enskild transaktion och hålla loggstorleken nere (förutsatt en enkel återställningsmodell). Min kod nedan gör detta i omgångar om 100 förhoppningsvis har du en befintlig PK som du kan utnyttja för att fortsätta där du slutade snarare än de upprepade skanningarna som kommer att ta allt längre tid mot slutet.
  3. använd ALTER TABLE ... ALTER COLUMN för att markera kolumnen som NOT NULL . Detta kräver att hela tabellen låses och skannas för att validera ändringen men kräver inte mycket loggning.
  4. Använd ALTER TABLE ... SWITCH för att göra kolumnen till en identitetskolumn. Detta är enbart en metadataändring.

Exempelkod nedan

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


  1. Gruppera och summera raddata i kolumner i MS-SQL?

  2. Ställ in SQLAlchemy att använda PostgreSQL SERIAL för identitetsgenerering

  3. Vad är det för fel med denna SQL DELETE FROM-syntax?

  4. MySQL Boolean tinyint(1) håller värden upp till 127?