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

前端 未结 12 1830
情话喂你
情话喂你 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 15:46

    I think this depends on the SQL flavor you are using, but what if you took option 2, but at the very end alter table table to not null with the default value?

    Would it be fast, since it sees all the values are not null?

    0 讨论(0)
  • 2020-12-02 15:47

    Here's what I would try:

    • Do a full backup of the database.
    • Add the new column, allowing nulls - don't set a default.
    • Set SIMPLE recovery, which truncates the tran log as soon as each batch is committed.
    • The SQL is: ALTER DATABASE XXX SET RECOVERY SIMPLE
    • Run the update in batches as you discussed above, committing after each one.
    • Reset the new column to no longer allow nulls.
    • Go back to the normal FULL recovery.
    • The SQL is: ALTER DATABASE XXX SET RECOVERY FULL
    • Backup the database again.

    The use of the SIMPLE recovery model doesn't stop logging, but it significantly reduces its impact. This is because the server discards the recovery information after every commit.

    0 讨论(0)
  • 2020-12-02 15:48

    1) Add the column to the table with a default value:

    ALTER TABLE MyTable ADD MyColumn int default 0
    

    2) Update the values incrementally in the table (same effect as accepted answer). Adjust the number of records being updated to your environment, to avoid blocking other users/processes.

    declare @rowcount int = 1
    
    while (@rowcount > 0)
    begin           
    
        UPDATE TOP(10000) MyTable SET MyColumn = 0 WHERE MyColumn IS NULL       
        set @rowcount = @@ROWCOUNT
    
    end
    

    3) Alter the column definition to require not null. Run the following at a moment when the table is not in use (or schedule a few minutes of downtime). I have successfully used this for tables with millions of records.

    ALTER TABLE MyTable ALTER COLUMN MyColumn int NOT NULL
    
    0 讨论(0)
  • 2020-12-02 15:51

    Vertically segment the table. This means you will have two tables, with the same primary key, and exactly the same number of records... One will be the one you already have, the other will have just the key, and the new Non-Null column (with default value) . Modify all Insert, Update, and delete code so they keep the two tables in synch... If you want you can create a view that "joins" the two tables together to create a single logical combination of the two that appears like a single table for client Select statements...

    0 讨论(0)
  • 2020-12-02 15:53

    You could:

    1. Start a transaction.
    2. Grab a write lock on your original table so no one writes to it.
    3. Create a shadow table with the new schema.
    4. Transfer all the data from the original table.
    5. execute sp_rename to rename the old table out.
    6. execute sp_rename to rename the new table in.
    7. Finally, you commit the transaction.

    The advantage of this approach is that your readers will be able to access the table during the long process and that you can perform any kind of schema change in the background.

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

    I ran into this problem for my work also. And my solution is along #2.

    Here are my steps (I am using SQL Server 2005):

    1) Add the column to the table with a default value:

    ALTER TABLE MyTable ADD MyColumn varchar(40) DEFAULT('')
    

    2) Add a NOT NULL constraint with the NOCHECK option. The NOCHECK does not enforce on existing values:

    ALTER TABLE MyTable WITH NOCHECK
    ADD CONSTRAINT MyColumn_NOTNULL CHECK (MyColumn IS NOT NULL)
    

    3) Update the values incrementally in table:

    GO
    UPDATE TOP(3000) MyTable SET MyColumn = '' WHERE MyColumn IS NULL
    GO 1000
    
    • The update statement will only update maximum 3000 records. This allow to save a chunk of data at the time. I have to use "MyColumn IS NULL" because my table does not have a sequence primary key.

    • GO 1000 will execute the previous statement 1000 times. This will update 3 million records, if you need more just increase this number. It will continue to execute until SQL Server returns 0 records for the UPDATE statement.

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