Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I want to add a column to a Sql Server table with about 10M rows. I think this query would eventually finish adding the column I want:

alter table T
add mycol bit not null default 0

but it's been going for several hours already. Is there any shortcut to get a "not null default 0" column inserted into a large table? Or is this inherently really slow?

This is Sql Server 2000. Later on I have to do something similar on Sql Server 2008.

share|improve this question

9 Answers 9

up vote 2 down vote accepted

Depending on your row size, table size, indexes, etc, I've seen SQL Server 2000 grind away for several hours (4-5ish hours) before FINALLY completing.

The worst thing you can do right now is "panic" and hard kill the thing. Let it run itself out.

In the future, you may wish to try doing what Farseeker mentioned and create a second (empty) structure and copy your records over that way.

  • The longer the table row, the longer it will take.
  • The more indexes you have on that table, the longer it will take.
  • If you add a default value (which you did), it will take longer.
  • If you have heavy usage on the server it will take longer.
  • If you don't lock that database or put it in single user mode, it will take longer.

When I have to do ugly stuff like this I try and do it at night... like 2am when nobody is on it (and maintentance is NOT running on the server).

Good luck! :-)

share|improve this answer

Did you happen to have a number of indexes for your table, and may even be a clustered index on your table T?

I also had problem adding a new column (it is an identity column). The table had 9.3 million rows, and it has one non-clustered index on the primary key.

For some reason if we drop the index for table T, follow by adding the column, then add back the index for table T. It was basically 60X faster on the Standard SQLServer 2008 .

I haven't figure out why it speeded up so much, hopefully someone can give me answer for this.

share|improve this answer
    
The reason the process speeds up 60x when the index is dropped is because: When you have an index, SQL server has to arrange the records in the table in a particular order. If you have an index on a column that has: A B C F and you decide to add "D", this record will have to be inserted between "C" and "F". The server has to first find the position and then insert the record. Hence the time consuming operation while inserting data on indexed tables. –  user149731 Dec 15 '12 at 2:34
    
@Terminator This is only correct if you are talking about a CLUSTERED index. A regular index does not affect table order - it simply stores a key value and an index into the database table (usually in a btree or similar structure). The reason index slows down the ALTER TABLE command is because each index needs to be updated (for 10M rows per index) -- a substantial amount of extra disk I/O and number-crunching. –  voretaq7 Dec 15 '12 at 4:25

You could try performing each step of the operation in a separate batch, e.g.

alter table T add mycol bit null
go
update T set mycol = 0
go
alter table T alter column mycol bit not null
go
alter table T add default 0 for mycol
go

Advantages are:

  • You get better feedback on the progress of the operation, since it is now 4 separate batches each taking roughly 1/4 of the time.
  • It reduces the likelihood of timeout errors when running it from client-side code.
  • I find that it sometimes improves performance.

You could also try dropping all nonclustered indexes on the table before making the change, and restoring them afterwards. Adding a column may well involve large-scale page splits or other low-level re-arrangements, and you could do without the overhead of updating nonclustered indexes while that is going on.

share|improve this answer
    
This approach is highly recommended. If necessary, you can even break that second step into chunks so you are only updating a subset of rows at a time, either based on primary key ranges, or by using SET ROWCOUNT (for sql 2000) or UPDATE TOP 1000 (for SQL 2005/2008). –  BradC Jul 30 '09 at 13:01

I have done similar things in a table with at least 65million rows and it did not take that long. Do you have enough memory and a enough performance in the disk system

If you want to speed up the process you can remove all indexes execpt clustered index and foreign key constraints before you alter the table, but it has to be done when the system is not use, or else you may end up with inconcistent data. But in the end you will need to apply the foreign keys and the indexes before you are done, but you will ease the pain for the transaction log, at least if you run in simple recovery model. And in SQL server 2008 you can build the indexes with ONLINE=on and SORT_IN_TEMPDB=on

Håkan Winther

share|improve this answer

At one training course I had a conversation with a couple of DBAs from the DoD. They manage MySQL databases of 100TB and more. Table changes are done with dump and load but that obviously requires some down time. They also mentioned they don't like doing this with databases over 10TB because of the time taken.

The data is dumped, they didn't specify what to but I'd assume SQL files. The tables are then truncated and the schema altered as required. The data is then reloaded.

share|improve this answer

Hours for 10m rows is far too long. Check that nothing is holding locks open on the table.

share|improve this answer

This will take quite a while. Its because you are adding the default value. This is causing the SQL Server to update all the rows in a single transaction. Ensure that noone else is using the table as this will cause blocking of your process.

share|improve this answer

Hmm, 10M rows is a quite few, but it's not outside the realm of MSSQL and that does seem very slow.

We had a table with a huge row size (poorly designed) and over 10M rows. When we had to modify the structure, it was def. very slow, so what we did was (to keep the table online, and this is rough from memory because it was a long time ago):

  • Created new table with the suffix "C" (for Conversion) and new structure (i.e. same as old one, but with new column/index/etc)
  • SELECT * INTO tableC FROM table
  • sp_rename 'table' 'tableOld'
  • sp_rename 'tableC' 'table'

This way it doesn't matter how long the conversion takes, as the old data is online. It might cause issues with rows being written to the table whilst the conversion takes place though (this wasn't an issue for us as the data was only written once daily, but queried thousands of times an hour) so you might want to investigate that.

share|improve this answer

You are not really going to shortcut something like this - no matter what you do SQL Server is going to have to do some processing on all the rows in the table.

You could ensure it runs as fast as possible by making sure that your data files and logs are on separate drives and the other usual recommendations.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.