将值设置为 table 中超过 500 万行的新日期时间列
Set value to a new datetime column in a table with over 5 million rows
我有一个名为 Table 的示例,它有超过 500 万行。
我想知道创建新的 DateTime
列的最有效方法,该列不允许空值且默认值为 Now。由于行数过多,仅设置值会失败。
我想到的计划涉及:
1) 创建一个允许空值的新列。
ALTER TABLE Example
ADD RecordDate datetime
GO
2) 一次将列的值设置为 GETDATE()
1000(或更多,如果可能)行。
3) 一旦所有行都有一个值,我将更改该列以不允许空值。
ALTER TABLE Example
ALTER COLUMN RecordDate datetime NOT NULL
我不确定完成第 2 步的最有效方法是什么。所以这就是我想要的一些提示。
我建议:
ALTER TABLE Example ADD COLUMN RecordDate datetime NOT NULL DEFAULT getdate();
无论您如何尝试,您都将不得不重写所有数据记录以在每个页面上为该值添加额外的字节——即使该值为 NULL。
我认为以下内容可以最大限度地减少对数据的更改:
ALTER TABLE Example ADD _RecordDate datetime;
ALTER TABLE Example ADD FirstDateTime as (cast(<current datetime> as datetime));
ALTER TABLE Example ADD RecordDate as COALESCE(_RecordDate, FirstDateTime);
转念一想,页面上的space还是要保留给_RecordDate
的,所以第一种方法应该是最好的。
另一种选择是使用相同的主键和记录日期设置另一个 table。这需要 left join
来获取信息,但只有在访问该列时才需要。
米兰
您可以在第 1 步尝试此脚本:
ALTER TABLE Example ADD RecordDate DATETIME NOT NULL DEFAULT GETDATE()
现在您不需要步骤 #2 和 #3。
要在具有顺序 ID 的大型 table 中工作,分批应用更新,此方法可行:
DECLARE @startID bigint
DECLARE @endID bigint
SELECT @startID=min(ID) from Example
WHILE @startID IS NOT NULL BEGIN
SELECT @endID=MAX(ID) FROM (
SELECT top(1000) ID from Example where ID>=@startID ORDER BY ID
) t
update Example
set RecordDate = GETDATE()
where ID between @startID and @endID AND RecordDate IS NULL
IF @@ROWCOUNT=0 BEGIN
SET @startID=NULL
END ELSE BEGIN
SET @startID=@endID
END
END
批量大小由
控制
SELECT top(1000) ID from Example where ID>=@startID ORDER BY ID
根据需要调整 1000 以确保每个更新快速完成。我已经使用这种技术分批更新了数亿行,每次更新大约 100000 行。
我有一个名为 Table 的示例,它有超过 500 万行。
我想知道创建新的 DateTime
列的最有效方法,该列不允许空值且默认值为 Now。由于行数过多,仅设置值会失败。
我想到的计划涉及:
1) 创建一个允许空值的新列。
ALTER TABLE Example
ADD RecordDate datetime
GO
2) 一次将列的值设置为 GETDATE()
1000(或更多,如果可能)行。
3) 一旦所有行都有一个值,我将更改该列以不允许空值。
ALTER TABLE Example
ALTER COLUMN RecordDate datetime NOT NULL
我不确定完成第 2 步的最有效方法是什么。所以这就是我想要的一些提示。
我建议:
ALTER TABLE Example ADD COLUMN RecordDate datetime NOT NULL DEFAULT getdate();
无论您如何尝试,您都将不得不重写所有数据记录以在每个页面上为该值添加额外的字节——即使该值为 NULL。
我认为以下内容可以最大限度地减少对数据的更改:
ALTER TABLE Example ADD _RecordDate datetime;
ALTER TABLE Example ADD FirstDateTime as (cast(<current datetime> as datetime));
ALTER TABLE Example ADD RecordDate as COALESCE(_RecordDate, FirstDateTime);
转念一想,页面上的space还是要保留给_RecordDate
的,所以第一种方法应该是最好的。
另一种选择是使用相同的主键和记录日期设置另一个 table。这需要 left join
来获取信息,但只有在访问该列时才需要。
米兰
您可以在第 1 步尝试此脚本:
ALTER TABLE Example ADD RecordDate DATETIME NOT NULL DEFAULT GETDATE()
现在您不需要步骤 #2 和 #3。
要在具有顺序 ID 的大型 table 中工作,分批应用更新,此方法可行:
DECLARE @startID bigint
DECLARE @endID bigint
SELECT @startID=min(ID) from Example
WHILE @startID IS NOT NULL BEGIN
SELECT @endID=MAX(ID) FROM (
SELECT top(1000) ID from Example where ID>=@startID ORDER BY ID
) t
update Example
set RecordDate = GETDATE()
where ID between @startID and @endID AND RecordDate IS NULL
IF @@ROWCOUNT=0 BEGIN
SET @startID=NULL
END ELSE BEGIN
SET @startID=@endID
END
END
批量大小由
控制SELECT top(1000) ID from Example where ID>=@startID ORDER BY ID
根据需要调整 1000 以确保每个更新快速完成。我已经使用这种技术分批更新了数亿行,每次更新大约 100000 行。