具有巨大性能问题的不同***记录
Posted
技术标签:
【中文标题】具有巨大性能问题的不同***记录【英文标题】:Distinct Top Records having huge performance Issue 【发布时间】:2021-09-12 23:46:15 【问题描述】:我有两个包含大量数据集的表,我正在尝试根据可选的搜索条件过滤数据。
Table 1 : Item
Table 2 : ScanCode
Item 可以有零个或 n 个 ScanCode,因此它们之间是一对 0 或多个关系,这就是我在 ScanCode 表上留下联接的原因,我正在尝试通过可选的 ScanCode 搜索让 Item 数据与 ScanCode 联接。
Declare @p_scanCode BIGINT = NULL, @p_limit INT = 500
SELECT TOP(@p_limit) i.ItemCode, i.StandardDescription,i.ItemType
FROM Item i
LEFT OUTER JOIN ScanCode sc
ON sc.FK_ItemCode = i.ItemCode
WHERE ((@p_scanCode IS NULL) OR (@p_scanCode IS NOT NULL AND sc.ScanCode = @p_scanCode))
ORDER BY ItemCode
上面的查询工作得很好,但由于我们有多个 ScanCode 用于一个项目,我们将在结果集中有重复,所以我更改了查询以包括 distinct。
Declare @p_scanCode BIGINT = NULL, @p_limit INT = 500
SELECT DISTINCT TOP(@p_limit) i.ItemCode, i.StandardDescription,i.ItemType
FROM Item i
LEFT OUTER JOIN ScanCode sc
ON sc.FK_ItemCode = i.ItemCode
WHERE ((@p_scanCode IS NULL) OR (@p_scanCode IS NOT NULL AND sc.ScanCode = @p_scanCode))
ORDER BY ItemCode
在查询上添加 distinct 后,现在需要 30 多秒才能获得结果,而以前需要不到 1 秒。 ScanCode 表很大,有 1200 万条数据。
我如何在没有任何性能问题的情况下根据提供的限制获得不同的***记录。
请提出建议。
【问题讨论】:
性能相关问题我们需要看执行计划。 缺少上下文,但听起来你有一个典型的kitchen sink search issue。而且使用没有 ORDER BY 子句的 TOP 通常是一个逻辑缺陷。 请通过brentozar.com/pastetheplan分享执行计划 @SM或者谢谢你,你给我的厨房水槽搜索帮助了我 【参考方案1】:你只需要从Item
输出项目吗? ScanCode
仅作为过滤器起作用?好像你需要exists
。如果关系是 1:many 那么你不需要担心distinct
。
declare
@p_scanCode bigint = null,
@p_limit int = 500
select
top (@p_limit) i.ItemCode, i.StandardDescription,i.ItemType
from item i
where @p_scanCode is null
or exists (
select 0
from scanCode sc
where sc.FK_ItemCode = i.ItemCode
and scanCode = @p_scanCode
)
【讨论】:
我不能在 where 子句中使用存在,因为 scanCode 是可选的,我们可以有 0 或 n 个扫描码,所以我留下了可选的搜索条件加入 抱歉,我重新设计了过滤器以满足该需求。如果 p_scancode 为空,则输出所有记录,否则仅输出具有现有 p_scanCode 的记录。这是否符合您的需求? 感谢 pwilcox,但他们可以选择将 p_scanCode 作为过滤器传递,如果他们通过 p_scanCode 我只需要过滤匹配的扫描码项目,否则获得前 500 个项目也可以有零或 n 个扫描码,如果我放scanCode = @p_Scancode 在子查询中需要很长时间才能得到结果 我再次编辑以匹配您的最后一条语句:'如果我将 scanCode = @p_scancode 放在子查询中......'。我以为我做到了,但一定是删除太多了。抱歉,它让它变慢了。希望其他人有一个好的解决方案。 小心点。动态查询听起来像一个创可贴。从长远来看,我会继续寻找非动态解决方案。祝你好运!【参考方案2】:使用条件连接和动态查询可以解决这个问题,因为问题是与 ScanCode 表连接时出现重复项,如果没有提供扫描码,我们可以进行条件连接,我们不加入,所以我们不会得到重复。如果提供了 ScanCode,那么每个扫描码将只有一个项目,在这种情况下我们不会得到重复。
此外,如果我们对 top(@p_limit) 记录使用动态限制,则在查询结束时需要 OPTION (RECOMPILE),这样它就不会使用具有先前限制的缓存执行计划,并且性能会下降。
Declare @p_scanCode BIGINT = '12345', @p_limit INT = 500
DECLARE @sql nvarchar(max) = N'
SELECT TOP(@p_limit) i.ItemCode, i.StandardDescription
FROM Item i '
+
CASE WHEN @p_scanCode IS NOT NULL THEN
N' LEFT OUTER JOIN SCANCODE AS SC
ON I.ItemCode = SC.FK_RetailItemCode
AND GETDATE() BETWEEN SC.EffectiveDate AND SC.TerminationDate ' ELSE N'' END
+
'WHERE 1 = 1'
+ CASE WHEN @p_scanCode IS NOT NULL THEN
N' AND sc.ScanCode = @p_scanCode' ELSE N'' END
+
' ORDER BY I.ItemCode asc OPTION (RECOMPILE)'
print @sql
【讨论】:
以上是关于具有巨大性能问题的不同***记录的主要内容,如果未能解决你的问题,请参考以下文章