2011-08-23 20 views
6

Mam tabelę bazy danych, która ma ~ 40 000 000 wierszy. Chcę dodać kolumnę tożsamości do tej tabeli. Jak to zrobić w sposób przyjazny dla dziennikarzy?Jak dodać kolumnę tożsamości do istniejącej tabeli bazy danych, która ma dużą liczbę wierszy

Kiedy należy wykonać następujące czynności:

ALTER TABLE table_1 
    ADD id INT IDENTITY 

to tylko zapełnia całą przestrzeń dziennika.

Czy istnieje sposób, aby zrobić to w sposób przyjazny dla dziennikarzy? Baza danych znajduje się na serwerze SQL Server 2008.

Dzięki, Mohan.

+2

Czy to jest MySQL, SQL Server, PostGres, Oracle? – JNK

+7

wyłącz dziennik, dodaj kolumnę, włącz rejestr. –

+0

Czy nie powinna to być odpowiedź, a nie tylko komentarz? –

Odpowiedz

4

Ogólny proces będzie prawdopodobnie dużo wolniejszy, z większym ogólnym obciążeniem blokowania, ale jeśli zależy Ci tylko na rozmiarze dziennika transakcji, spróbuj wykonać następujące czynności.

  1. Dodaj kolumnę z zerową liczbą całkowitą bez tożsamości (zmiana tylko metadanych).
  2. Wpisz kod, aby zaktualizować tę wartość, używając unikatowych ciągłych liczb całkowitych w pakietach. Zmniejszy to rozmiar każdej pojedynczej transakcji i zmniejszy rozmiar dziennika (zakładając prosty model odzyskiwania). Mój kod poniżej robi to w partiach po 100, mam nadzieję, że masz istniejący PK, który możesz wykorzystać do pobrania w miejscu, w którym przerwałeś, zamiast powtarzających się skanów, które pod koniec będą coraz dłuższe.
  3. użyj ALTER TABLE ... ALTER COLUMN, aby oznaczyć kolumnę jako NOT NULL. Będzie to wymagało zablokowania i zeskanowania całej tabeli w celu zatwierdzenia zmiany, ale nie będzie wymagać dużej ilości rejestrowania.
  4. Użyj kolumny ALTER TABLE ... SWITCH, aby kolumna stała się kolumną tożsamości. Jest to zmiana tylko metadanych.

Przykład kodu poniżej

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

Czy masz ramy czasowe, kiedy możesz przenieść bazę danych w tryb pojedynczego użytkownika? Najlepiej zrobić to na prod w trybie pojedynczego użytkownika i ze wszystkimi użytkownikami z wyjątkiem zablokowanego dba. – HLGEM

1

ja właśnie zrobiłem to do mojego tabeli, która ma ponad 2700 wierszy. Przejdź do projektu tabeli, dodaj nową kolumnę, ustaw ją tak, aby nie zezwalała na wartości null, ustaw kolumnę jako kolumnę tożsamości we właściwościach kolumny i powinna to zrobić. Dosłownie po prostu zrobiłem to mniej niż 5 minut temu i zadziałało to dla mnie. Proszę wybrać odpowiedź, jeśli odpowie na to pytanie.

Powiązane problemy