繁体   English   中英

更改表的SQL Server性能更改列更改数据类型

[英]SQL Server performance for alter table alter column change data type

我们需要将某些列的数据类型从int更改为bigint。 不幸的是,其中一些表很大,大约有7-10百万行(但不宽)。

Alter表alter列永远在这些表上使用。 有没有更快的方法来实现这一目标?

巧合的是,大约3个小时前,我不得不做一些非常相似的事情。 该表是3500万行,它相当宽,并且这样做总是要花很多时间:

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列,分批更新新列,然后在其上设置约束。

使用正确的列类型和索引创建所需的新表。 (在旧表中编写脚本,然后更改名称。)

插入新表(列列表),然后从old_table中选择*;

重命名old_table old_table_back,重命名new_table old_table。

在新表上创建旧索引,在旧表上删除所有ri约束,然后在新表上创建它们。 同样,您的rdbms将具有一些简单的方法来生成脚本来执行此操作。

我只是遇到了这个问题...一个表中有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';

几周前,我刚遇到一个有6.39亿行的表。 我最终创建了一个新表,并在“批次”中复制了数据。 在主服务器上花费了大约2天,而复制花费了3天才能全部复制。 然后,我修改了旧表的所有视图和proc。 这使我可以清理一些问题,例如摆脱不想要的列并选择(在某些情况下)更好的索引。 在所有数据都移到sql更改之后,然后我删除了旧表。

一团糟,但现在明智些。 如果系统寿命长,并且有几百万行的可能性,请使用大整数来标识主键。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM