How do you add a NOT NULL Column to a large table in SQL Server?

前端 未结 12 1831
情话喂你
情话喂你 2020-12-02 15:42

To add a NOT NULL Column to a table with many records, a DEFAULT constraint needs to be applied. This constraint causes the entire ALTER TABLE command to take a long time to

相关标签:
12条回答
  • 2020-12-02 16:02

    I had a similar problem, and went for your option #2. It takes 20 minutes this way, as opposed to 32 hours the other way!!! Huge difference, thanks for the tip. I wrote a full blog entry about it, but here's the important sql:

    Alter table MyTable
    Add MyNewColumn char(10) null default '?';
    go
    
    update MyTable set MyNewColumn='?' where MyPrimaryKey between 0 and 1000000
    go
    update MyTable set MyNewColumn='?' where MyPrimaryKey between 1000000 and 2000000
    go
    update MyTable set MyNewColumn='?' where MyPrimaryKey between 2000000 and 3000000
    go
    ..etc..
    
    Alter table MyTable
    Alter column MyNewColumn char(10) not null;
    

    And the blog entry if you're interested: http://splinter.com.au/adding-a-column-to-a-massive-sql-server-table

    0 讨论(0)
  • 2020-12-02 16:02

    I had a similar problem and I went with modified #3 approach. In my case the database was in SIMPLE recovery mode and the table to which column was supposed to be added was not referenced by any FK constraints.

    Instead of creating a new table with the same schema and copying contents of original table, I used SELECT…INTO syntax.

    According to Microsoft (http://technet.microsoft.com/en-us/library/ms188029(v=sql.105).aspx)

    The amount of logging for SELECT...INTO depends on the recovery model in effect for the database. Under the simple recovery model or bulk-logged recovery model, bulk operations are minimally logged. With minimal logging, using the SELECT… INTO statement can be more efficient than creating a table and then populating the table with an INSERT statement. For more information, see Operations That Can Be Minimally Logged.

    The sequence of steps :

    1.Move data from old table to new while adding new column with default

     SELECT  table.*,   cast (‘default’ as nvarchar(256)) new_column
     INTO    table_copy 
     FROM    table
    

    2.Drop old table

     DROP TABLE  table
    

    3.Rename newly created table

     EXEC sp_rename 'table_copy',  ‘table’
    

    4.Create necessary constraints and indexes on the new table

    In my case the table had more than 100 million rows and this approach completed faster than approach #2 and log space growth was minimal.

    0 讨论(0)
  • 2020-12-02 16:02

    I would use CURSOR instead of UPDATE. Cursor will update all matching records in batch, record by record -- it takes time but not locks table.

    If you want to avoid locks use WAIT.

    Also I am not sure, that DEFAULT constrain changes existing rows. Probably NOT NULL constrain use together with DEFAULT causes case described by author.

    If it changes add it in the end So pseudocode will look like:

    -- without NOT NULL constrain -- we will add it in the end
    ALTER TABLE table ADD new_column INT DEFAULT 0
    
    DECLARE fillNullColumn CURSOR LOCAL FAST_FORWARD
        SELECT 
            key
        FROM
            table WITH (NOLOCK)
        WHERE
            new_column IS NULL
    
    OPEN fillNullColumn
    
    DECLARE 
        @key INT
    
    FETCH NEXT FROM fillNullColumn INTO @key
    
    WHILE @@FETCH_STATUS = 0 BEGIN
         UPDATE
             table WITH (ROWLOCK)
         SET
             new_column = 0 -- default value
         WHERE
             key = @key
    
         WAIT 00:00:05 --wait 5 seconds, keep in mind it causes updating only 12 rows per minute
    
         FETCH NEXT FROM fillNullColumn INTO @key
    END
    
    CLOSE fillNullColumn
    DEALLOCATE fillNullColumn
    
    ALTER TABLE table ALTER COLUMN new_column ADD CONSTRAIN xxx
    

    I am sure that there are some syntax errors, but I hope that this help to solve your problem.

    Good luck!

    0 讨论(0)
  • 2020-12-02 16:08

    If you want the column in the same table, you'll just have to do it. Now, option 3 is potentially the best for this because you can still have the database "live" while this operation is going on. If you use option 1, the table is locked while the operation happens and then you're really stuck.

    If you don't really care if the column is in the table, then I suppose a segmented approach is the next best. Though, I really try to avoid that (to the point that I don't do it) because then like Charles Bretana says, you'll have to make sure and find all the places that update/insert that table and modify those. Ugh!

    0 讨论(0)
  • 2020-12-02 16:09

    Admitted that this is an old question. My colleague recently told me that he was able to do it in one single alter table statement on a table with 13.6M rows. It finished within a second in SQL Server 2012. I was able to confirm the same on a table with 8M rows. Something changed in later version of SQL Server?

    Alter table mytable add mycolumn char(1) not null default('N');
    
    0 讨论(0)
  • 2020-12-02 16:10

    Just to update this with the latest information.

    In SQL Server 2012 this can now be carried out as an online operation in the following circumstances

    1. Enterprise Edition only
    2. The default must be a runtime constant

    For the second requirement examples might be a literal constant or a function such as GETDATE() that evaluates to the same value for all rows. A default of NEWID() would not qualify and would still end up updating all rows there and then.

    For defaults that qualify SQL Server evaluates them and stores the result as the default value in the column metadata so this is independent of the default constraint which is created (which can even be dropped if no longer required). This is viewable in sys.system_internals_partition_columns. The value doesn't get written out to the rows until next time they happen to get updated.

    More details about this here: online non-null with values column add in sql server 2012

    0 讨论(0)
提交回复
热议问题