2011-08-23 46 views
6

Tôi có bảng cơ sở dữ liệu có ~ 40 000 000 hàng. Tôi muốn thêm một cột nhận dạng vào bảng này. Làm thế nào để làm điều đó một cách thân thiện với log?Cách thêm cột nhận dạng vào bảng cơ sở dữ liệu hiện có có số hàng lớn

Khi tôi làm như sau:

ALTER TABLE table_1 
    ADD id INT IDENTITY 

này chỉ lấp đầy toàn bộ không gian đăng nhập.

Có cách nào để làm điều đó một cách thân thiện với nhật ký không? Cơ sở dữ liệu nằm trên SQL Server 2008.

Cảm ơn, Mohan.

+2

Đây có phải là MySQL, SQL Server, PostGres, Oracle không? – JNK

+7

vô hiệu hóa nhật ký, thêm cột, bật nhật ký. –

+0

Đó không phải là câu trả lời và không chỉ là một bình luận? –

Trả lời

4

Quá trình tổng thể có thể sẽ chậm hơn rất nhiều với tổng chi phí khóa cao hơn nhưng nếu bạn chỉ quan tâm đến kích thước nhật ký giao dịch, bạn có thể thử các bước sau.

  1. Thêm cột số nguyên không có giá trị rỗng (chỉ thay đổi siêu dữ liệu).
  2. Viết mã để cập nhật điều này với các số nguyên tuần tự duy nhất theo lô. Điều này sẽ giảm kích thước của từng giao dịch riêng lẻ và giảm kích thước nhật ký (giả sử mô hình khôi phục đơn giản). Mã của tôi dưới đây thực hiện điều này theo lô 100 hy vọng bạn có một PK hiện có, bạn có thể tận dụng để tiếp tục từ nơi bạn đã dừng thay vì quét lặp đi lặp lại sẽ mất nhiều thời gian để kết thúc.
  3. sử dụng ALTER TABLE ... ALTER COLUMN để đánh dấu cột là NOT NULL. Điều này sẽ yêu cầu toàn bộ bảng bị khóa và quét để xác thực thay đổi nhưng không yêu cầu ghi nhật ký nhiều.
  4. Sử dụng ALTER TABLE ... SWITCH để biến cột thành cột nhận dạng. Đây là siêu dữ liệu chỉ thay đổi.

Ví dụ Mã Dưới

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

Bạn có khung thời gian khi bạn có thể đặt dataqbase vào chế độ người dùng đơn lẻ không? Tốt nhất là làm điều này trên prod trong chế độ người dùng duy nhất và với tất cả người dùng ngoại trừ dba bị khóa. – HLGEM

1

Tôi chỉ làm điều này để bàn của tôi rằng có hơn 2700 dòng. Đi đến thiết kế của bảng, thêm cột mới, đặt nó để không cho phép null, đặt cột làm cột nhận dạng trong thuộc tính cột và điều đó sẽ làm điều đó. Tôi thực sự đã làm điều này ít hơn 5 phút trước và nó đã làm việc cho tôi. Vui lòng chọn làm câu trả lời nếu điều này trả lời câu hỏi của bạn.

Các vấn đề liên quan