大數據量表中,增長一個NOT NULL的新列

 

此次,發佈清洗列表功能,須要對數據庫進行升級。MailingList表加個IfCleaning字段,全部的t_User*表加個IfCleaned字段。sql

 

腳本以下數據庫

對全部的t_User表執行express

alter table t_User** add IfCleaned bit default(0) not nullless

Mailing list表執行測試

alter table t_MailingList add IfCleanning bit default(0) not null大數據

 

簡簡單單的兩個語句,在執行過程當中,Solution生產環境機器變得沒法訪問,遠程連不上,Solution程序也連不上了。後來不得不打電話到蕭山機房叫機房那邊把機器強制重啓。ui

 

當時就分析緣由應該是整個腳本須要執行的t_User表太多,表中數據太大,引發數據庫將內存或者磁盤資源佔滿了。t_User表中有幾千萬數據的表也存在的。this

 

之後對大數據量的表進行操做時要格外當心,無論是程序對錶的操做,仍是數據庫升級時對錶的操做,都須要在大數據量下進行完備的測試後才能夠進行發佈。spa

 

通過討論和研究,新的腳本以下,將原先一步的腳本分爲好多步,並且,在第三步中又分爲好多步。方法主要參考右側的StackOverFlow的文章。http://stackoverflow.com/questions/287954/how-do-you-add-a-not-null-column-to-a-large-table-in-sql-serverorm

 

第一步,增長新列,賦予默認值,容許爲NULL

alter table t_User***** add NewColumnIfCleaned bit default(0)

這樣,表中原有記錄的值均爲NULL

但如有新的記錄插入進來,新紀錄的該列值爲默認的0.

 

第二步,增長一個NOT NULL的約束,並設置NOCHECK

alter table t_User***** with nocheck add constraint NewColumnIfCleaned_NotNull check (NewColumnIfCleaned is not null)

這樣,表中原有記錄仍可保持爲NULL

若插入新紀錄,則會有這個NOT NULL的約束

 

第三步,分批將原有記錄更新爲0. 一次執行3000,完整的腳本以下。

原文章中的Go 1000的方法在咱們這裏並不適用,由於咱們要GO多少次是不肯定的,要根據t_user表數據量來計算出來的。

 

declare @i int, @strSql nvarchar(2000), @table nvarchar(200), @start int, @strNum nvarchar(100), @preUpate int, @totalCount int, @goCount int, @siteDelay datetime, @dbDelay datetime, @tbDelay datetime;

 

select @preUpate=3000, @siteDelay='00:00:02', @dbDelay='00:05:00', @tbDelay='00:00:01';

 

declare @time1 datetime;

select @time1=GETDATE();

 

--更新Site****

use [Comm100.Site****]

select @totalCount=0,@goCount=0,@i=0,@start=10000000;

while @i<500

begin

select @strNum= CONVERT(nvarchar(50),@start+@i);

select @table='t_User'+@strNum;

select @strSql='if exists (select top 1 * from [dbo].[sysobjects] where [Id]=object_id(N''[dbo].['+@table+']'') and objectproperty(id, N''IsUserTable'') = 1)

begin

if exists(select * from syscolumns where id=OBJECT_ID('''+@table+''') and name=''IfCleaned'')

begin

select @totalCount1=count(0) from '+@table+' where IfCleaned is null;

end

end

';

 

--print @strSql;

exec sp_executesql @strSql,N'@totalCount1 int output',@totalCount output;

 

if(@totalCount>0)

begin

select @goCount=@totalCount / @preUpate +1;

        while (@goCount>0)

         begin      

select @strSql='       

update top('+CONVERT(nvarchar(10),@preUpate)+') '+@table+' set IfCleaned=0 where IfCleaned is null;

';

--print @strSql;       

exec(@strSql);

select @goCount=@goCount-1;

waitfor delay @tbDelay;

end

end

set @i=@i+1;

waitfor delay @siteDelay;

end

 

select DATEDIFF(MILLISECOND,@time1,GETDATE());

 

注:在新的SQL Server 2012中,在表中增長一個NOT NULL的字段,狀況好像有所不一樣,

Adding NOT NULL Columns as an Online Operation

In SQL Server 2012 Enterprise Edition, adding a NOT NULL column with a default value is an online operation when the default value is a runtime constant. This means that the operation is completed almost instantaneously regardless of the number of rows in the table. This is because the existing rows in the table are not updated during the operation; instead, the default value is stored only in the metadata of the table and the value is looked up as needed in queries that access these rows. This behavior is automatic; no additional syntax is required to implement the online operation beyond the ADD COLUMN syntax. A runtime constant is an expression that produces the same value at runtime for each row in the table regardless of its determinism. For example, the constant expression "My temporary data", or the system function GETUTCDATETIME() are runtime constants. In contrast, the functions NEWID() or NEWSEQUENTIALID() are not runtime constants because a unique value is produced for each row in the table. Adding a NOT NULL column with a default value that is not a runtime constant is always performed offline and an exclusive (SCH-M) lock is acquired for the duration of the operation.

While the existing rows reference the value stored in metadata, the default value is stored on the row for any new rows that are inserted and do not specify another value for the column. The default value stored in metadata is moved to an existing row when the row is updated (even if the actual column is not specified in the UPDATE statement), or if the table or clustered index is rebuilt.

Columns of type varchar(max), nvarchar(max), varbinary(max), xml, text, ntext, image, hierarchyid, geometry, geography, or CLR UDTS, cannot be added in an online operation. A column cannot be added online if doing so causes the maximum possible row size to exceed the 8,060 byte limit. The column is added as an offline operation in this case.

相關文章
相關標籤/搜索