如何将标识列添加到具有大量行的现有数据库表

时间:2011-08-23 15:09:38

标签: sql sql-server sql-server-2008 identity

我有一个数据库表,其中有大约40 000 000行。我想在此表中添加一个标识列。如何以对数友好的方式做到这一点?

当我执行以下操作时:

ALTER TABLE table_1
  ADD id INT IDENTITY

这只会填满整个日志空间。

有没有办法以对数友好的方式做到这一点?该数据库位于SQL Server 2008上。

谢谢, 莫汉。

3 个答案:

答案 0 :(得分:4)

整个过程可能会因为更多的整体锁定开销而慢得多,但如果您只关心事务日志大小,则可以尝试以下操作。

  1. 添加可为空的整数非标识列(仅元数据更改)。
  2. 编写代码以批量更新独特的顺序整数。这将减少每个单独事务的大小并保持日志大小(假设简单的恢复模型)。我的下面的代码分批进行100次,希望你有一个现有的PK,你可以利用它从你离开的地方拿起而不是重复的扫描,这将会越来越长。
  3. 使用ALTER TABLE ... ALTER COLUMN将列标记为NOT NULL。这将需要锁定和扫描整个表以验证更改,但不需要太多日志记录。
  4. 使用ALTER TABLE ... SWITCH将列设为标识列。这是仅元数据更改。
  5. 下面的示例代码

    /*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 :(得分:1)

有两种方法可以将标识列添加到包含现有数据的表中:

  1. 使用标识创建一个新表,将数据复制到此新表,然后删除现有表,然后重命名临时表。

  2. 使用identity&amp;创建一个新列删除现有列

  3. 参考:http://cavemansblog.wordpress.com/2009/04/02/sql-how-to-add-an-identity-column-to-a-table-with-data/

答案 2 :(得分:1)

我刚刚在我的桌子上做了超过2700行。转到表的设计,添加新列,将其设置为不允许空值,将列设置为列属性中的标识列,并且应该执行此操作。我在不到5分钟前完成了这项工作,这对我有用。如果这回答了您的问题,请选择答案。