我们需要将某些列的数据类型从int更改为bigint。不幸的是,其中一些表很大,大约有7到1000万行(但不是很宽)。
Alter table alter column将永远占用这些表。有没有更快的方法来实现这一目标?
答案 0 :(得分:8)
巧合的是,我必须在3小时前做一些非常相似的事情。这张桌子是35米的行,它相当宽,而且只需这样做就可以了:
alter table myTable add myNewColumn int not null default 0;
这就是我最终的目标:
alter table myTable add myNewColumn int null;
while 1=1
begin
update top (100000) myTable
set
myNewColumn = 0
where
myNewColumn is null;
if @@ROWCOUNT = 0 break;
end
alter table myTable alter column myNewColumn int not null;
alter table myTable add constraint tw_def_myNewColumn default (0) for myNewColumn;
这一次,alter table
陈述几乎是即时的。这需要大约7-8分钟(在慢速服务器上)进行更新批处理。我推测SQL Server在我的原始查询中生成撤消以恢复值,但我没想到会开始。
无论如何,在你的情况下,也许类似的东西会有所帮助。您可以尝试添加新的bigint列,批量更新新列,然后在其上设置约束。
答案 1 :(得分:2)
使用正确的columntypes和索引创建所需的新表。 (编写旧表,并更改名称。)
插入新表(列列表)select * from old_table;
重命名old_table old_table_back,重命名new_table old_table。
在新表上创建旧索引,删除旧表上的任何ri约束并在新表上创建它们。同样,您的rdbms将有一些简单的方法来生成脚本来执行此操作。
答案 2 :(得分:1)
我刚遇到这个问题......一张包含447,732,310条记录的表格。如果一位同事提出了一个很棒的解决方案,只需要大约24分钟就可以将数据复制到新表中,大约需要40分钟来创建索引。
以下是我们的所作所为:
--Get ntiles of idOrders, split up into 100 groups - 1:20 minutes
IF(OBJECT_ID('TEMPDB..#x')) IS NOT NULL
DROP TABLE #x
SELECT nt, MIN(idOrder) idOrderMin, MAX(idOrder) idOrderMax
INTO #X
FROM (
SELECT idOrder, NTILE(100) OVER(ORDER BY idOrder) nt
FROM (
SELECT DISTINCT idOrder FROM order_raw_fields
) X
) Y
GROUP BY nt
-- view results
--SELECT * FROM #x ORDER BY idOrderMin
-- create new table
SELECT TOP 0 *
INTO ORDER_RAW_FIELDS_Intl
FROM ORDER_RAW_FIELDS
ALTER TABLE dbo.ORDER_RAW_FIELDS_Intl
ALTER COLUMN value nvarchar(500)
--Build queries
SELECT 'insert into ORDER_RAW_FIELDS_Intl select * from order_raw_fields
where idOrder >= ' + CAST(idOrderMIn AS VARCHAR(100)) + ' and idOrder <= ' + CAST(idOrderMax AS varchar) InsertStmt
INTO #inserts
FROM #X
ORDER BY idOrderMin
DECLARE insertCursor CURSOR LOCAL FAST_FORWARD FOR
SELECT InsertStmt
FROM #inserts
OPEN insertCursor
-- 24:04 minute execution time to match
DECLARE @insertStmt NVARCHAR(125)
FETCH NEXT FROM insertCursor INTO @insertStmt
WHILE @@FETCH_STATUS = 0
BEGIN
--EXECUTE @insertStmt
EXECUTE sp_executesql @statement=@insertStmt
PRINT 'Execution Complete: ' + @insertStmt
FETCH NEXT FROM insertCursor INTO @insertStmt
END
CLOSE insertCursor
DEALLOCATE insertCursor
-- Add indexes
-- 21:37 minutes completion time
ALTER TABLE [dbo].[ORDER_RAW_FIELDS_Intl] ADD CONSTRAINT [PK_ORDER_RAW_FIELDS_Intl] PRIMARY KEY CLUSTERED
(
[idRow] ASC,
[idOrder] ASC,
[remoteFieldName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 92) ON [PRIMARY]
GO
-- 13:45 minutes completion time
CREATE NONCLUSTERED INDEX [IX_idOrder_remoteFieldName2] ON [dbo].[ORDER_RAW_FIELDS_Intl]
(
[idOrder] ASC,
[remoteFieldName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 94) ON [PRIMARY]
GO
-- drop table
TRUNCATE TABLE [dbo].[ORDER_RAW_FIELDS]
DROP TABLE [dbo].[ORDER_RAW_FIELDS]
-- renamed new table to old tables's name
EXEC sp_rename 'ORDER_RAW_FIELDS_Intl', 'ORDER_RAW_FIELDS';
答案 3 :(得分:0)