Sql-Server

在 100 毫米記錄上使用 JOIN 更新,如何更好地做到這一點?(在 T-SQL 中)

  • November 19, 2020

我需要更新單個表中的 1 億條記錄,實際上,通過用簡單的 ID 替換列的 varchar 值來規範化表。(我說的是“替換”,但實際上我是在將 ID 寫入另一列。)

我想要實現的是規範化數據集。尚未標準化的數據沒有索引。我的想法是,我不會在原始值上建立索引,而是在更新完成后索引將用 tinyint 值替換 varchar 值的外鍵。

UPDATE A
SET A.AutoClassID = B.AutoClassID
FROM AutoDataImportStaging.dbo.Automobile as A
JOIN AutoData.dbo.AutoClass as B on (A.AutoClassName = B.AutoClassName)

背景

  • 在 Server 2008 R2 上使用 MSSQL 2008 R2
  • 伺服器有 8 GB RAM
  • 伺服器有一個 RAID10,7200 RPM SATA(不是很好,我知道,在生產中這只會讀取數據而不會寫入數據;加上最近的 HD 短缺,這使得成本變得必要)
  • 伺服器具有雙四核 Xeon CPU
  • 機器沒有做任何其他事情(目前專用於開發,只有這個過程)
  • 打開了簡單的日誌記錄(? - 但它仍然記錄以便它可以回滾嗎?)
  • 請注意,查詢引用了兩個不同的數據庫,這是值得的
  • 更新表中記錄的“寬度”為 455 字節

執行期間的資源

  • 物理 RAM 已用盡
  • 磁碟 I/O 已用盡
  • CPU 幾乎沒有做任何事情(阻塞點是 I/O)
  • 執行時間已經 14 小時,而且還在繼續!

我懷疑一些事情,比如我需要原始數據的索引,即使我將在規範化更新後刪除列 (AutoClassName)。我還想知道我是否應該一次只循環一條記錄而不是 JOIN,這在我開始時似乎很荒謬,但現在似乎會更快。

我應該如何更快地更改我剩餘的標準化更新(類似於這個)的方法?

您正在嘗試將其作為單個(非常大)事務來執行。相反,請以較小的批次進行更新。

您還將受益於:

  • AutoData.dbo.AutoClass.AutoClassName 上的臨時索引
  • 更多記憶體。更多的記憶體。

我會採取不同的方法。

無需更新現有表,只需建構一個包含您需要的新表即可。

這幾乎肯定會更快:

SELECT DISTINCT
   AutoClassID,
   <Other fields>
INTO
   AutoDataImportStaging.dbo.Automobile
FROM
   AutoData.dbo.AutoClass

正如目前所寫,發生了很多邏輯操作:

  • 讀取 A.AutoClassName 的所有值
  • 讀取 B.AutoClassName 的所有值
  • 比較 A 值和 B 值
  • 匹配集合中,讀取 B.AutoClassID 的所有值
  • 通過存在的任何索引將 A.AutoClassId 的現有值更新為 B.AutoClassId 值

引用自:https://dba.stackexchange.com/questions/20499