在 100 毫米记录上使用 JOIN 更新,如何做得更好?(在 T-SQL 中)

Chr*_*gna 11 sql-server-2008 sql-server t-sql

我需要更新单个表中的 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)
Run Code Online (Sandbox Code Playgroud)

背景

  • 在 Server 2008 R2 上使用 MSSQL 2008 R2
  • 服务器有 8 GB RAM
  • 服务器有一个 RAID10, 7200 RPM SATA(不太好,我知道,在生产中这只会读取数据而不会写入数据;加上最近的 HD 短缺使得这对成本来说是必要的)
  • 服务器具有双四核至强 CPU
  • 机器没有做其他任何事情(目前专用于开发,只有这个过程)
  • 简单日志记录已打开(? - 但它是否仍然记录以便它可以回滚?)
  • 请注意,查询引用了两个不同的数据库,这是值得的
  • 表中记录更新的“宽度”为 455 字节

执行期间的资源

  • 物理内存已满
  • 磁盘 I/O 已满
  • CPU 几乎不做任何事情(阻塞点是 I/O)
  • 运行时间已经 14 小时,而且还在增加!

我怀疑一些事情,比如我需要原始数据的索引,即使我会在规范化更新后删除列 (AutoClassName)。我还想知道我是否应该一次循环一条记录而不是 JOIN,这在我开始时看起来很荒谬,但现在看来会更快。

我应该如何更快地更改剩余标准化更新(类似于此更新)的方法?

JNK*_*JNK 10

我会采取不同的方法。

无需更新现有表,只需构建一个包含您所需内容的新表。

这几乎肯定会更快:

SELECT DISTINCT
    AutoClassID,
    <Other fields>
INTO
    AutoDataImportStaging.dbo.Automobile
FROM
    AutoData.dbo.AutoClass
Run Code Online (Sandbox Code Playgroud)

正如目前所写,有很多逻辑操作正在发生:

  • 读取 A.AutoClassName 的所有值
  • 读取 B.AutoClassName 的所有值
  • 比较 A 和 B 值
  • 在匹配集中,读取 B.AutoClassID 的所有值
  • 通过存在的任何索引将 A.AutoClassId 的现有值更新为 B.AutoClassId 值


Mar*_*ith 7

您正在尝试将其作为单个(非常大的)事务来执行。相反,以较小的批次进行更新。

您还将受益于:

  • AutoData.dbo.AutoClass.AutoClassName 上的临时索引
  • 更多内存。更多的内存。


小智 5

一次循环一排表格,不会更快!

正如您所怀疑和确认的那样,这将受到 I/O 限制——拥有一个磁盘,读取、写入、事务日志和(任何)临时工作空间都将竞争相同的 I/O。

简单恢复仍将记录事务,但日志将被检查点清除。您的初始日志大小和自动增长设置可能会导致一些 I/O 速度变慢 - 事务日志需要增长以适应更改。

您是否尝试过索引 AutoClassName 字段?有多少种不同的 AutoClass 值?

您可能需要根据 i/o 的限制批量更新。所以更新100万,检查点,重复......