Sql server 如何在SQLServer中向大型表中添加NOTNULL列?
要向包含多条记录的表中添加NOTNULL列,需要应用默认约束。如果表非常大,此约束会导致整个ALTER TABLE命令运行很长时间。这是因为: 假设:Sql server 如何在SQLServer中向大型表中添加NOTNULL列?,sql-server,Sql Server,要向包含多条记录的表中添加NOTNULL列,需要应用默认约束。如果表非常大,此约束会导致整个ALTER TABLE命令运行很长时间。这是因为: 假设: 默认约束修改现有记录。这意味着数据库需要增加每个记录的大小,这会导致它将完整数据页上的记录转移到其他数据页,这需要时间 默认更新作为原子事务执行。这意味着需要增加事务日志,以便在必要时执行回滚 事务日志跟踪整个记录。因此,即使只修改了单个字段,日志所需的空间也将基于整个记录的大小乘以现有记录的大小。这意味着,即使两个表的记录总数相同,向具有小记录
我认为这取决于您正在使用的SQL风格,但是如果您选择了选项2,但最后使用默认值将table table改为notnull,会怎么样
因为它看到所有的值都不是空的,所以它会很快吗?垂直分割表格。这意味着您将有两个表,具有相同的主键,并且记录数完全相同。。。一个将是您已经拥有的,另一个将只有键和新的非空列(具有默认值)。
修改所有Insert、Update和delete代码,使它们保持两个表的同步。。。如果需要,您可以创建一个视图,将两个表“连接”在一起,以创建两个表的单一逻辑组合,该组合看起来就像客户端Select语句的单一表…以下是我将尝试的内容:
- 对数据库进行完整备份
- 添加新列,允许空值-不要设置默认值
- 设置简单恢复,它在提交每个批时立即截断传输日志李>
- SQL是:ALTER DATABASE XXX SET RECOVERY SIMPLE
- 如上文所述,分批运行更新,并在每次更新后提交
- 重置新列以不再允许空值
- 回到正常的完全恢复状态李>
- SQL为:ALTER DATABASE XXX SET RECOVERY FULL
- 再次备份数据库李>
简单恢复模型的使用并没有停止日志记录,但它显著降低了其影响。这是因为服务器在每次提交后都会丢弃恢复信息。我会使用游标而不是更新。游标将批量更新所有匹配的记录,一条记录一条记录地更新——这需要时间,但不会锁定表 如果要避免锁定,请使用等待 另外,我不确定默认约束是否会更改现有行。 可能不是空约束与作者描述的默认原因一起使用 如果它改变了,最后添加它 所以伪代码看起来像:
-- 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
我确信有一些语法错误,但我希望
帮助解决你的问题
祝你好运 如果要将列放在同一个表中,只需这样做即可。现在,选项3可能是最好的选择,因为在执行此操作时,您仍然可以使数据库处于“活动”状态。如果您使用选项1,则在操作发生时表被锁定,然后您真的被卡住了 如果您不在乎该列是否在表中,那么我认为分段方法是次优方法。尽管如此,我还是尽量避免这样做(以至于我不这么做),因为就像Charles Bretana所说的那样,您必须确保找到所有更新/插入该表的位置并对其进行修改。啊 你可以:
这种方法的优点是,读者可以在漫长的过程中访问表,并且可以在后台执行任何形式的模式更改 我也遇到了类似的问题,选择了你的选项2。 这种方式需要20分钟,而另一种方式需要32小时!!!差别很大,谢谢你的提示。 我写了一篇关于它的完整博客文章,但下面是重要的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;
如果您感兴趣,请访问以下博客:
我在工作中也遇到了这个问题。我的解决方案是2 以下是我的步骤(我正在使用SQL Server 2005): 1) 添加c
ALTER TABLE MyTable ADD MyColumn varchar(40) DEFAULT('')
ALTER TABLE MyTable WITH NOCHECK
ADD CONSTRAINT MyColumn_NOTNULL CHECK (MyColumn IS NOT NULL)
GO
UPDATE TOP(3000) MyTable SET MyColumn = '' WHERE MyColumn IS NULL
GO 1000
SELECT table.*, cast (‘default’ as nvarchar(256)) new_column
INTO table_copy
FROM table
DROP TABLE table
EXEC sp_rename 'table_copy', ‘table’
Alter table mytable add mycolumn char(1) not null default('N');
ALTER TABLE MyTable ADD MyColumn int default 0
declare @rowcount int = 1
while (@rowcount > 0)
begin
UPDATE TOP(10000) MyTable SET MyColumn = 0 WHERE MyColumn IS NULL
set @rowcount = @@ROWCOUNT
end
ALTER TABLE MyTable ALTER COLUMN MyColumn int NOT NULL