sql >> Database >  >> RDS >> Sqlserver

Een identiteitskolom toevoegen aan een bestaande databasetabel die een groot aantal rijen heeft

Het algehele proces zal waarschijnlijk een stuk langzamer zijn met meer algemene vergrendelingsoverhead, maar als u alleen om de grootte van het transactielogboek geeft, kunt u het volgende proberen.

  1. Voeg een nullable integer niet-identiteitskolom toe (alleen metadata wijzigen).
  2. Schrijf code om dit bij te werken met unieke opeenvolgende gehele getallen in batches. Dit verkleint de omvang van elke afzonderlijke transactie en houdt de loggrootte laag (uitgaande van een eenvoudig herstelmodel). Mijn onderstaande code doet dit in batches van 100, hopelijk heb je een bestaande PK die je kunt gebruiken om verder te gaan waar je was gebleven in plaats van de herhaalde scans die tegen het einde steeds langer zullen duren.
  3. gebruik ALTER TABLE ... ALTER COLUMN om de kolom te markeren als NOT NULL . Hiervoor moet de hele tabel worden vergrendeld en gescand om de wijziging te valideren, maar er is niet veel logboekregistratie vereist.
  4. Gebruik ALTER TABLE ... SWITCH om van de kolom een ​​identiteitskolom te maken. Dit is alleen een wijziging in metadata.

Voorbeeldcode hieronder

/*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. Voorwaardelijke telling/som in selectie

  2. laravel 5 inner join en groeperen op query syntaxisfout

  3. Houdt PostgreSQL zijn pl*-interpreters voortdurend geladen?

  4. Analyseer Big Data met Microsoft Azure Tools