rsj*_*ffe 12 performance sql-server parallelism sql-server-2016 query-performance
我有一个查询在我们的服务器上运行大约需要 3 个小时——而且它没有利用并行处理。(大约 115 万条记录dbo.Deidentified, 300 条记录dbo.NamesMultiWord)。服务器可以访问 8 个内核。
UPDATE dbo.Deidentified
WITH (TABLOCK)
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml),
DE461 = dbo.ReplaceMultiWord(DE461),
DE87 = dbo.ReplaceMultiWord(DE87),
DE15 = dbo.ReplaceMultiWord(DE15)
WHERE InProcess = 1;
Run Code Online (Sandbox Code Playgroud)
和ReplaceMultiword是一个过程定义为:
SELECT @body = REPLACE(@body,Names,Replacement)
FROM dbo.NamesMultiWord
ORDER BY [WordLength] DESC
RETURN @body --NVARCHAR(MAX)
Run Code Online (Sandbox Code Playgroud)
是呼吁ReplaceMultiword阻止形成平行计划吗?有没有办法重写它以允许并行?
ReplaceMultiword 以降序运行,因为某些替换是其他替换的简短版本,我希望最长的匹配成功。
例如,可能有“乔治华盛顿大学”和另一个来自“华盛顿大学”。如果“华盛顿大学”比赛是第一场,那么“乔治”就会被甩在后面。
从技术上讲,我可以使用 CLR,只是我不熟悉如何使用。
Mar*_*ith 11
UDF 正在阻止并行性。它也是导致该线轴的原因。
您可以使用 CLR 和编译后的正则表达式来进行搜索和替换。只要存在所需的属性,它就不会阻止并行性,并且可能比REPLACE每个函数调用执行 300 个 TSQL操作快得多。
示例代码如下。
DECLARE @X XML =
(
SELECT Names AS [@find],
Replacement AS [@replace]
FROM dbo.NamesMultiWord
ORDER BY [WordLength] DESC
FOR XML PATH('x'), ROOT('spec')
);
UPDATE dbo.Deidentified WITH (TABLOCK)
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml, @X),
DE461 = dbo.ReplaceMultiWord(DE461, @X),
DE87 = dbo.ReplaceMultiWord(DE87, @X),
DE15 = dbo.ReplaceMultiWord(DE15, @X)
WHERE InProcess = 1;
Run Code Online (Sandbox Code Playgroud)
这取决于 CLR UDF 的存在,如下所示(这DataAccessKind.None应该意味着假脱机消失以及用于万圣节保护的假脱机并且不需要,因为它不访问目标表)。
DECLARE @X XML =
(
SELECT Names AS [@find],
Replacement AS [@replace]
FROM dbo.NamesMultiWord
ORDER BY [WordLength] DESC
FOR XML PATH('x'), ROOT('spec')
);
UPDATE dbo.Deidentified WITH (TABLOCK)
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml, @X),
DE461 = dbo.ReplaceMultiWord(DE461, @X),
DE87 = dbo.ReplaceMultiWord(DE87, @X),
DE15 = dbo.ReplaceMultiWord(DE15, @X)
WHERE InProcess = 1;
Run Code Online (Sandbox Code Playgroud)
底线:向子句添加条件WHERE并将查询拆分为四个单独的查询,每个字段一个查询,允许 SQL Server 提供并行计划,并使查询运行速度比没有在子句中进行额外测试的情况下快 4 倍WHERE。在没有测试的情况下将查询分成四个并不能做到这一点。在不拆分查询的情况下添加测试也没有效果。优化测试将总运行时间从原来的 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());
}
Run Code Online (Sandbox Code Playgroud)
并且,在 中internal class ReplaceSpecification,我添加了代码来针对正则表达式执行测试
internal bool IsMatch(string inputString)
{
if (Regex == null)
return false;
return Regex.IsMatch(inputString);
}
Run Code Online (Sandbox Code Playgroud)
如果在一条语句中测试所有字段,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);
Run Code Online (Sandbox Code Playgroud)
然而,如果这些字段被分成单独的语句,则使用并行工作计划,并且我的 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;
Run Code Online (Sandbox Code Playgroud)
执行时间46分钟。行统计显示大约 0.5% 的记录至少有一个正则表达式匹配。执行计划:

现在,拖延时间的主要因素是该WHERE条款。WHERE然后,我用作为 CLR 实现的Aho-Corasick 算法替换了子句中的正则表达式测试。这将总时间减少到 3 分 6 秒。
这需要进行以下更改。加载 Aho-Corasick 算法的程序集和函数。将条款更改WHERE为
WHERE InProcess = 1 AND dbo.ContainsWordsByObject(ISNULL(FieldBeingTestedGoesHere,'x'), @ac) = 1;
Run Code Online (Sandbox Code Playgroud)
并在第一个之前添加以下内容UPDATE
DECLARE @ac NVARCHAR(32);
SET @ac = dbo.CreateAhoCorasick(
(SELECT NAMES FROM dbo.NamesMultiWord FOR XML RAW, root('root')),
'en-us:i'
);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
838 次 |
| 最近记录: |