簡體   English   中英

更新1.2億條記錄的最快方式

[英]Fastest way to update 120 Million records

我需要在一個1.2億記錄表中初始化一個值為-1的新字段。

Update table
       set int_field = -1;

我讓它運行了5個小時才取消它。

我嘗試運行它,事務級別設置為讀取未提交的相同結果。

Recovery Model = Simple.
MS SQL Server 2005

如何更快地完成這項工作?

更新120M記錄表的唯一有效方法是使用SELECT語句填充第二個表。 這樣做時你必須小心。 說明如下。


簡單案例

對於沒有聚集索引的表,在w / out並發DML的時間內:

  • SELECT *, new_col = 1 INTO clone.BaseTable FROM dbo.BaseTable
  • 在新表上重新創建索引,約束等
  • 切換舊的和新的w / ALTER SCHEMA ... TRANSFER。
  • 放下舊桌子

如果無法創建克隆架構,則同一架構中的其他表名稱將起作用。 切記在切換后重命名所有約束和觸發器(如果適用)。


非簡單案例

首先,在不同的模式下重新創建具有相同名稱的BaseTable ,例如clone.BaseTable 使用單獨的模式將在以后簡化重命​​名過程。

  • 如果適用,請包括聚簇索引 請記住,主鍵和唯一約束可能是聚類的,但不一定如此。
  • 如果適用,請包括標識列和計算列
  • 包括您的新INT列 ,無論它在哪里。
  • 不包括以下任何內容:
    • 觸發器
    • 外鍵約束
    • 非聚集索引/主鍵/唯一約束
    • 檢查約束或默認約束。 默認值沒有多大區別,但我們試圖將事情保持在最低限度。

然后,測試你的插件w / 1000行:

-- assuming an IDENTITY column in BaseTable
SET IDENTITY_INSERT clone.BaseTable ON
GO
INSERT clone.BaseTable WITH (TABLOCK) (Col1, Col2, Col3)
SELECT TOP 1000 Col1, Col2, Col3 = -1
FROM dbo.BaseTable
GO
SET IDENTITY_INSERT clone.BaseTable OFF

檢查結果。 如果一切按順序出現:

  • 截斷克隆表
  • 確保數據庫處於批量記錄或簡單恢復模型中
  • 執行完整插入。

這需要一段時間,但不會像更新那么長。 完成后,檢查克隆表中的數據以確保一切正確。

然后,重新創建所有非群集主鍵/唯一約束/索引和外鍵約束(按此順序)。 如果適用,重新創建默認值並檢查約束。 重新創建所有觸發器。 在單獨的批處理中重新創建每個約束,索引或觸發器。 例如:

ALTER TABLE clone.BaseTable ADD CONSTRAINT UQ_BaseTable UNIQUE (Col2)
GO
-- next constraint/index/trigger definition here

最后,將dbo.BaseTable移動到備份架構並將clone.BaseTable到dbo架構(或者您的表應該存在的任何位置)。

-- -- perform first true-up operation here, if necessary
-- EXEC clone.BaseTable_TrueUp
-- GO
-- -- create a backup schema, if necessary
-- CREATE SCHEMA backup_20100914
-- GO
BEGIN TRY
  BEGIN TRANSACTION
  ALTER SCHEMA backup_20100914 TRANSFER dbo.BaseTable
  -- -- perform second true-up operation here, if necessary
  -- EXEC clone.BaseTable_TrueUp
  ALTER SCHEMA dbo TRANSFER clone.BaseTable
  COMMIT TRANSACTION
END TRY
BEGIN CATCH
  SELECT ERROR_MESSAGE() -- add more info here if necessary
  ROLLBACK TRANSACTION
END CATCH
GO

如果您需要釋放磁盤空間,可以在此時刪除原始表,盡管保持一段時間可能是謹慎的。

不用說,這理想情況下是離線操作。 如果您在執行此操作時有人修改數據,則必須使用架構開關執行校正操作。 我建議在dbo.BaseTable上創建一個觸發器,將所有DML記錄到一個單獨的表中。 在開始插入之前啟用此觸發器。 然后,在執行模式傳輸的同一事務中,使用日志表執行校正。 首先在數據子集上進行測試! Deltas很容易搞砸。

如果您有磁盤空間,則可以使用SELECT INTO並創建新表。 它的記錄最少,因此速度會快得多

select t.*, int_field = CAST(-1 as int)
into mytable_new 
from mytable t

-- create your indexes and constraints

GO

exec sp_rename mytable, mytable_old
exec sp_rename mytable_new, mytable

drop table mytable_old

我將任務分解為更小的單位。 為您的表測試不同的批處理大小間隔,直到找到最佳執行的間隔。 這是我過去使用過的一個示例。

declare @counter int 
declare @numOfRecords int
declare @batchsize int

set @numOfRecords = (SELECT COUNT(*) AS NumberOfRecords FROM <TABLE> with(nolock))
set @counter = 0 
set @batchsize = 2500

set rowcount @batchsize
while @counter < (@numOfRecords/@batchsize) +1
begin 
set @counter = @counter + 1 
Update table set int_field = -1 where int_field <> -1;
end 
set rowcount 0

如果您的int_field已編制索引,請在運行更新之前刪除索引。 然后再次創建索引......

對於1.2億人來說,5個小時似乎很多。

declare @cnt bigint
set @cnt = 1

while @cnt*100<10000000 
 begin

UPDATE top(100) [Imp].[dbo].[tablename]
   SET [col1] = xxxx       
 WHERE[col2] is null  

  print '@cnt: '+convert(varchar,@cnt)
  set @cnt=@cnt+1
  end
set rowcount 1000000
Update table set int_field = -1 where int_field<>-1

看看需要多快,調整和重復

我先嘗試的是
在更新之前首先刪除所有約束,索引,觸發器和全文索引。

如果上面的表現不夠好,我的下一步行動就是
創建一個包含1200萬條記錄的CSV文件,並使用bcp批量導入它。

最后,我創建了一個新的堆表(意思是沒有主鍵的表),在不同的文件組上沒有索引,用-1填充它。 對舊表進行分區,並使用“switch”添加新分區。

添加新列(“初始化新字段”)並為每個現有行設置單個值時,我使用以下策略:

ALTER TABLE MyTable
 add NewColumn  int  not null
  constraint MyTable_TemporaryDefault
   default -1

ALTER TABLE MyTable
 drop constraint MyTable_TemporaryDefault

如果列可以為空並且您不包含“聲明”約束,則對於所有行,該列將設置為null。

聽起來像索引問題,就像Pabla Santa Cruz提到的那樣。 由於您的更新不是條件更新,因此您可以刪除列並使用DEFAULT值重新添加它。

一般來說,建議如下:

  1. 刪除或僅禁用表格中的所有INDEXES,TRIGGERS,CONSTRAINTS;
  2. 更頻繁地執行COMMIT(例如,在每1000個已更新的記錄之后);
  3. 使用select ... into。

但在特殊情況下,您應該選擇最合適的解決方案或它們的組合。

還要記住,某些時候索引可能很有用,例如,當您通過某些條件執行非索引列的更新時。

如果表有一個可以迭代的索引,我會將update top(10000)語句放在while循環中移動數據。 這將使事務日志保持苗條,並且不會對磁盤​​系統產生如此巨大的影響。 另外,我建議使用maxdop選項(將其設置為接近1)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM