【问题标题】:UPDATE and REPLACE for lots of rows更新和替换很多行
【发布时间】:2021-09-08 14:56:40
【问题描述】:

我的表中有 1700 万行,其中一些在 [url] 列中包含一个 URL,我想替换所有行中 URL 的一部分。

我的表中有 800 万行需要更新。

我已经稍微优化了我的查询,批量替换了 4,000 个,但仍然需要很长时间:

declare @Rows INT,
@BatchSize INT;

SET @BatchSize = 4000;
SET @Rows = @BatchSize; -- initialize just to enter the loop
while (@Rows = @BatchSize)
BEGIN
UPDATE TOP (@BatchSize) [dbo].[table]
SET
  [url] = replace([url], 
  '?sv=2019-12-12&foo=bar',
  '?sv=2020-02-10&bar=foo')
where [url] like '%foo=bar'
END;

您知道我可以如何改进这项任务吗?

【问题讨论】:

  • 分页有帮助,因为只有 4K 行被写入事务日志。这个查询仍然很慢,因为它一遍又一遍地搜索表以寻找匹配项,每次迭代都会变慢,因为查询必须跳过更多被替换的行。将匹配的 ID/主键值提取到临时表中,并使用这些 ID 进行分页。
  • 这似乎是个好主意,您介意写一个答案,这样我就可以尝试并接受您的消息,如果可行的话?

标签: sql sql-server optimization


【解决方案1】:

问题可能是因为WHERE 子句,每个update 都需要扫描整个表。具有讽刺意味的是,一种解决方案是跳过批次。 UPDATE 将花费更长的时间,但它只会扫描表一次。

第二种选择是优化WHERE 子句的索引。该子句有三种方法:

  • 使用全文索引。
  • 创建“基于表达式”的索引,这在 SQL Server 中需要添加计算列,然后在计算列上建立索引。
  • 创建过滤索引。

第三种是最简单的方法。但是,唉,SQL Server 不允许在过滤索引中使用 like,因此它不适用于您的情况。

所以,试试这个版本:

alter table t add url_suffix as (right(url, 7);

create index idx_table_url_suffix on table(url_suffix);

然后您可以将where 逻辑表述为:

where url7 = 'foo=bar';

【讨论】:

  • 谢谢,“过滤索引”技术有点用。如果没有url_suffix 列上的索引,更新 4k 行大约需要 4 分钟,因此更新 800 万行需要 130 小时……有了索引,它需要一半的时间,但仍然需要很长时间。
  • 我接受了你的回答。我的查询花费了比周末更多的时间来遍历我的整个桌子,但它奏效了!谢谢
【解决方案2】:

您可能想看看 MySQL 字符串函数。它们可能允许您在 SQL 语句中完成所有操作(因为您只是在进行替换)。

类似:

更新table SET some_text_row = replace(some_text_row, 'some 短语', '其他短语') WHERE some_text_row LIKE '%some 短语%';

【讨论】:

  • 您为什么要查看 MySQL 字符串函数来解决 SQL Server 问题?实际上,实际更新本身并不是这里的问题。
  • 在 MySQL 中执行此操作即使不比 SQL Server 更糟糕,也一样糟糕。执行这样的更新将阻塞整个表非常长时间,并可能在事务日志中写入多达 17M 的记录。这就是 OP 使用批处理的原因
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-23
  • 2011-07-28
  • 2012-11-10
  • 1970-01-01
  • 2021-05-19
  • 2014-10-26
相关资源
最近更新 更多