底线:在WHERE
子句中添加条件并将查询分为四个独立的查询,每个字段一个查询允许SQL Server提供并行计划,并使查询的运行速度是WHERE
子句的4 倍,而无需在子句中进行额外的测试。在没有测试的情况下将查询分为四个并没有做到这一点。添加测试而不拆分查询都没有。优化测试可以将总运行时间从最初的3个小时减少到3分钟。
我最初的UDF用了3小时16分钟来处理1,174,731行,并测试了1.216 GB的nvarchar数据。使用马丁·史密斯(Martin Smith)提供的CLR,执行计划仍然不是并行的,任务花费了3小时5分钟。
阅读该WHERE
标准可以帮助推动UPDATE
并行发展,我做了以下工作。我向CLR模块添加了一个函数,以查看该字段是否与正则表达式匹配:
[SqlFunction(IsDeterministic = true,
IsPrecise = true,
DataAccess = DataAccessKind.None,
SystemDataAccess = SystemDataAccessKind.None)]
public static SqlBoolean CanReplaceMultiWord(SqlString inputString, SqlXml replacementSpec)
{
string s = replacementSpec.Value;
ReplaceSpecification rs;
if (!cachedSpecs.TryGetValue(s, out rs))
{
var doc = new XmlDocument();
doc.LoadXml(s);
rs = new ReplaceSpecification(doc);
cachedSpecs[s] = rs;
}
return rs.IsMatch(inputString.ToString());
}
在中internal class ReplaceSpecification
,我添加了代码以针对正则表达式执行测试
internal bool IsMatch(string inputString)
{
if (Regex == null)
return false;
return Regex.IsMatch(inputString);
}
如果在单个语句中测试了所有字段,则SQL Server不会并行处理工作
UPDATE dbo.DeidentifiedTest
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml, @X),
DE461 = dbo.ReplaceMultiWord(DE461, @X),
DE87 = dbo.ReplaceMultiWord(DE87, @X),
DE15 = dbo.ReplaceMultiWord(DE15, @X)
WHERE InProcess = 1
AND (dbo.CanReplaceMultiWord(IndexedXml, @X) = 1
OR DE15 = dbo.ReplaceMultiWord(DE15, @X)
OR dbo.CanReplaceMultiWord(DE87, @X) = 1
OR dbo.CanReplaceMultiWord(DE15, @X) = 1);
执行时间超过4 1/2小时并仍在运行。执行计划:
但是,如果将字段分成单独的语句,则使用并行工作计划,并且我的CPU使用率从串行计划的12%变为并行计划(8核)的100%。
UPDATE dbo.DeidentifiedTest
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(IndexedXml, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE461 = dbo.ReplaceMultiWord(DE461, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE461, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE87 = dbo.ReplaceMultiWord(DE87, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE87, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE15 = dbo.ReplaceMultiWord(DE15, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE15, @X) = 1;
执行时间为46分钟。行统计数据显示,大约0.5%的记录至少有一个正则表达式匹配项。执行计划:
现在,拖延时间的主要因素是WHERE
条款。然后,我用实现为CLR WHERE
的Aho-Corasick算法替换了子句中的正则表达式测试。这将总时间减少到3分6秒。
这需要进行以下更改。加载Aho-Corasick算法的程序集和函数。将该WHERE
子句更改为
WHERE InProcess = 1 AND dbo.ContainsWordsByObject(ISNULL(FieldBeingTestedGoesHere,'x'), @ac) = 1;
并在第一个之前添加以下内容 UPDATE
DECLARE @ac NVARCHAR(32);
SET @ac = dbo.CreateAhoCorasick(
(SELECT NAMES FROM dbo.NamesMultiWord FOR XML RAW, root('root')),
'en-us:i'
);
SELECT @var = REPLACE ... ORDER BY
结构不能保证按预期工作。示例Connect项目(请参阅Microsoft的响应)。因此,切换到SQLCLR具有保证正确结果的附加优点,这总是很不错的。