我有一个数据库表,其中有大约40 000 000行。我想在此表中添加一个标识列。如何以对数友好的方式做到这一点?
当我执行以下操作时:
ALTER TABLE table_1
ADD id INT IDENTITY
这只会填满整个日志空间。
有没有办法以对数友好的方式做到这一点?该数据库位于SQL Server 2008上。
谢谢, 莫汉。
答案 0 :(得分:4)
整个过程可能会因为更多的整体锁定开销而慢得多,但如果您只关心事务日志大小,则可以尝试以下操作。
ALTER TABLE ... ALTER COLUMN
将列标记为NOT NULL
。这将需要锁定和扫描整个表以验证更改,但不需要太多日志记录。ALTER TABLE ... SWITCH
将列设为标识列。这是仅元数据更改。 下面的示例代码
/*Set up test table with just one column*/
CREATE TABLE table_1 ( original_column INT )
INSERT INTO table_1
SELECT DISTINCT
number
FROM master..spt_values
/*Step 1 */
ALTER TABLE table_1 ADD id INT NULL
/*Step 2 */
DECLARE @Counter INT = 0 ,
@PrevCounter INT = -1
WHILE @PrevCounter <> @Counter
BEGIN
SET @PrevCounter = @Counter;
WITH T AS ( SELECT TOP 100
* ,
ROW_NUMBER() OVER ( ORDER BY @@SPID )
+ @Counter AS new_id
FROM table_1
WHERE id IS NULL
)
UPDATE T
SET id = new_id
SET @Counter = @Counter + @@ROWCOUNT
END
BEGIN TRY;
BEGIN TRANSACTION ;
/*Step 3 */
ALTER TABLE table_1 ALTER COLUMN id INT NOT NULL
/*Step 4 */
DECLARE @TableScript NVARCHAR(MAX) = '
CREATE TABLE dbo.Destination(
original_column INT,
id INT IDENTITY(' + CAST(@Counter + 1 AS VARCHAR) + ',1)
)
ALTER TABLE dbo.table_1 SWITCH TO dbo.Destination;
'
EXEC(@TableScript)
DROP TABLE table_1 ;
EXECUTE sp_rename N'dbo.Destination', N'table_1', 'OBJECT' ;
COMMIT TRANSACTION ;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0
ROLLBACK TRANSACTION ;
PRINT ERROR_MESSAGE() ;
END CATCH ;
答案 1 :(得分:1)
有两种方法可以将标识列添加到包含现有数据的表中:
使用标识创建一个新表,将数据复制到此新表,然后删除现有表,然后重命名临时表。
使用identity&amp;创建一个新列删除现有列
参考:http://cavemansblog.wordpress.com/2009/04/02/sql-how-to-add-an-identity-column-to-a-table-with-data/
答案 2 :(得分:1)
我刚刚在我的桌子上做了超过2700行。转到表的设计,添加新列,将其设置为不允许空值,将列设置为列属性中的标识列,并且应该执行此操作。我在不到5分钟前完成了这项工作,这对我有用。如果这回答了您的问题,请选择答案。