我正在尝试对大型数据库中的字段执行数据清理。我有一个参考表,其中包含带有替换词的单词,如果您愿意,可以使用宏。我想以最有效的方式将这些更改应用于包含数百万行的表。话虽如此,让我在下面提供一些虚拟数据,以便您可以可视化该过程:
Street_Addresses 表:
Street_Name | Expanded_Name
------------------+--------------
100 Main St Ste 5 | NULL
25 10th Ave Apt 2 | NULL
75 Bridge Rd | NULL
Word_Substitutions 表:
Word | Replacement
-----+------------
St | Street
Ave | Avenue
Rd | Road
Ste | Suite
Apt | Apartment
所以更新后的最终结果如下:
Street_Name | Expanded_Name
------------------+--------------
100 Main St Ste 5 | 100 Main Street Suite 5
25 10th Ave Apt 2 | 25 10th Avenue Apartment 2
75 Bridge Rd | 75 Bridge Road
这里的挑战是需要进行大量替换,实际上是在单个值上进行多次替换。想到的最初想法是使用标量函数来封装这个逻辑。但正如您可以想象的那样,这在数百万行上并不高效。
CREATE FUNCTION Substitute_Words (@Text varchar(MAX))
RETURNS varchar(MAX) AS
BEGIN
SELECT @Text = REPLACE(' ' + @Text + ' ', ' ' + Word + ' ',
' ' + Replacement + ' ') FROM Word_Substitutions
RETURN LTRIM(RTRIM(@Text))
END
我决定改用基于集合的操作,并提出以下建议:
WHILE (1 = 1)
BEGIN
UPDATE A SET Expanded_Name = LTRIM(RTRIM(REPLACE(
' ' + ISNULL(A.Expanded_Name, A.Street_Name) + ' ',
' ' + W.Word + ' ', ' ' + W.Replacement + ' ')))
FROM Street_Addresses AS A
CROSS APPLY (SELECT TOP 1 Word, Replacement
FROM Word_Substitutions WHERE CHARINDEX(' ' + Word + ' ',
' ' + ISNULL(A.Expanded_Name, A.Street_Name) + ' ') > 0) AS W
IF (@@ROWCOUNT = 0)
BREAK
END
现在,根据我的实际数据集,这大约需要 2 个小时,如果可能的话,我想减少它 - 有人有优化建议吗?
更新:
通过只使用内部连接,我能够将执行时间减少到大约 5 分钟。我最初认为将更新与返回多行的内部联接一起使用是行不通的。更新似乎仍然有效,但源行将获得单个而不是多个更新。显然,SQL Server 为更新选择了一个随机结果行,而丢弃了其他行。
WHILE (1 = 1)
BEGIN
UPDATE A SET Expanded_Name = LTRIM(RTRIM(REPLACE(
' ' + ISNULL(A.Expanded_Name, A.Street_Name) + ' ',
' ' + W.Word + ' ', ' ' + W.Replacement + ' ')))
FROM Street_Addresses AS A
INNER JOIN Word_Substitutions AS W ON CHARINDEX(' ' + W.Word + ' ',
' ' + ISNULL(A.Expanded_Name, A.Street_Name) + ' ') > 0
IF (@@ROWCOUNT = 0)
BREAK
END