sac*_*lra -3 performance sql-server query-performance
Select *
from #temp1
join #temp2 on #temp2.mdx <> replace(#temp2.mdx,#temp1.mdx,'')
Run Code Online (Sandbox Code Playgroud)
上面的查询大约需要 30 分钟才能执行。我想减少这个时间。
#temp1 包含 100 000 条记录#temp2 包含 4 000 条记录#temp1.mdx并#temp2.mdx都varchar(max)列。temp2.mdx 是一个类似的公式subprocess[1].dp[2]/subprocess[1].dp[5],它可以达到任何长度。temp1.mdx 包含该公式的一部分。
我想根据 #temp2.mdx 的每个公式获取 #temp1.mdx 的所有行,就像 temp1.mdx 包含
和 temp2.mdx 包含
通过上述逻辑,我将得到 2 行 a/b 和 3 行 a/b*d 因为当你用 '' 替换 A/b 中的 A 时,它不等于 A/b,这样你就会找到所有该公式中使用的行。
temp2.mdx 的最大长度为 10213。
我试图在我的本地机器上运行这个查询,它是 3.1ghz 和 8gb ram。我还没有在实际服务器上尝试过。
这种类型的查询永远不会表现良好:
Select *
from #temp1 join #temp2 on #temp2.mdx <> replace(#temp2.mdx,#temp1.mdx,'')
Run Code Online (Sandbox Code Playgroud)
但是,如果您了解其性能不佳的原因,则可以使其性能更好。SQL Server 有三个选项来物理实现该连接:散列连接、合并连接和循环连接。哈希联接和合并联接都要求联接中至少有一个始终为真的相等条件,因此这些条件不符合此查询的条件。如果你试图强制他们,你会得到一个错误。因此,您必须执行循环连接,但无法创建可用于在嵌套循环连接的内侧进行查找的索引。本质上,您需要 SQL Server 对两个表进行交叉联接,并对每个行组合评估一次联接谓词。对于您的表大小,您需要计算谓词 4 亿次。
所以你对此能做些什么?您可以通过使连接谓词的计算成本尽可能低(因为您需要执行 4 亿次)并鼓励 SQL Server 并行执行查询来提高性能。查询优化器偏向于此类查询的并行计划。
让我们从降低连接谓词的成本开始。是否temp1.mdx总是适合的VARCHAR(8000)?的文档[REPLACE][1]说明如下:
string_pattern 是要查找的子字符串。string_pattern 可以是字符或二进制数据类型。string_pattern 不能是空字符串 (''),并且不能超过适合页面的最大字节数。
所以好像你可能会得到错误的结果。撇开这一点不谈,该REPLACE函数意味着您#temp2.mdx每次都需要处理整个字符串。如果您立即找到匹配项,您就不能提前退出。直觉上,这种任务感觉像是错误的功能。您可以改用 LIKE,但您需要注意自动转换为VARCHAR(MAX):
Select *
from #temp1
join #temp2 on #temp2.mdx LIKE CAST('%' AS VARCHAR(MAX)) + #temp1.mdx + CAST('%' AS VARCHAR(MAX))
Run Code Online (Sandbox Code Playgroud)
我不知道你的数据集是什么样的,但在我的机器上,这减少了 33% 的运行时间。如果您可以使用CHARINDEX,您可以做得更好,但只有在#temp1.mdx可以将其转换为VARCHAR(8000)不丢失数据的情况下才有效。
Select *
from #temp1
join #temp2 on charindex(#temp1.mdx, #temp2.mdx) > 0
Run Code Online (Sandbox Code Playgroud)
与原始查询相比,该语法节省了 50% 的运行时间。如果原始查询需要 30 分钟来执行并进行 4 亿次比较,那么这种变化就会加起来。
所有查询MAXDOP 1在我的机器上自然运行:
发生这种情况是因为并行计划不会降低嵌套循环内侧的成本。如果您确实需要提高性能,您可以考虑诱使 SQL Server 使用并行计划。尽管优化器采用了成本计算模型,但这种类型的查询非常适合并行化。我将使用未记录的跟踪标志 8649,它对生产使用不安全:
Select *
from #temp1
join #temp2 on charindex(#temp1.mdx, #temp2.mdx) > 0
OPTION (QUERYTRACEON 8649);
Run Code Online (Sandbox Code Playgroud)
在其他不繁忙的 4 CPU 服务器上,您可以看到查询运行速度比以前快 4 倍。将所有内容放在一起,您可能会看到 8 倍的加速。也许您需要 30 分钟的查询现在需要接近 4 分钟。
您可以使用一些技巧来避免选择所有列、表定义和假脱机。没有更多信息就不能说更多。