我一直在尝试改进一个SQL查询,它在同一个表上使用多个子查询,但条件不同,并且只检索每个子查询的第一个结果。
我将尝试简化用例:
我有一个表Products
,如下所示:
| 产品标识(_I)|参考文献|字段3|字段4|
| - -|- -|- -|- -|
| 一个|参考1|值1| val 3值|
| 2个|参考2|值2| val 4值|
还有另一个表History
:
| 历史记录标识(_I)|参考文献|实用代码|物理码|发行人|媒介|日期时间|
| - -|- -|- -|- -|- -|- -|- -|
| 一个|参考1| '测试'|'油管测试'|'0个'|'音频'|'日期'|
| 2个|参考2| '电话'|'呼叫方'|'一'|'视频(& V)'|'日期'|
| 三个|参考2| '测试'|'呼叫方'|'二'|'测试(& T)'|'日期'|History
是一个日志表,因此包含很多值。
现在我有一个这样的查询
SELECT
p.reference,
p.field3, p.field4,
(SELECT TOP 1 a_date
FROM history h
WHERE h.reference = p.reference
AND physicalcode = 'TST'
AND issue = 0
ORDER BY a_date DESC) AS latest_date_issue_0,
(SELECT TOP 1 a_date
FROM history h
WHERE h.reference = p.reference
AND physicalcode = 'TST'
AND issue = 1
ORDER BY a_date DESC) AS latest_date_issue_1
(SELECT TOP 1 a_date
FROM history h
WHERE h.reference = p.reference
AND utilcode = 'phone'
ORDER BY a_date DESC) AS latest_date_phone,
(SELECT TOP 1 media
FROM history h
WHERE h.reference = p.reference
AND utilcode = 'phone'
ORDER BY a_date DESC) AS latest_media,
-- and so on with many possible combinations
-- Note that there are more than this few fields on the tables I work on.
WHERE
p.field3 = 'valX',
p.field4 = 'valY'
FROM
products p
我如何合并每个子选择?甚至是几个相似的来提高性能?
历史记录是一个非常大的表,多次选择它会大大降低查询速度。
主要的问题是我每次只需要第一个值。
谢谢你的时间,我希望找到一个更好的方法来处理这个问题!
我尝试使用ROW_NUMBER()
,但找不到合适的使用方法。
我还尝试使用WITH
创建一个临时表,将历史记录中的每一种可能性分组,但情况更糟。
编辑:执行计划https://www.brentozar.com/pastetheplan/?id=Sy1AKIsUs
2条答案
按热度按时间qni6mghb1#
您可以将相关的子查询(您称之为“子选择”)转换为独立的子查询,然后对它们进行JOIN操作。这样,每个子查询只需运行一次。我将为您演示如何对第一个子查询执行此操作。
下面是替换第一个子查询的子查询。
这将提供一个虚拟表,其中包含历史表中与问题中的条件匹配的每个引用编号的最新日期。
然后,您可以将其连接到主表,如下所示:
这些子查询也可以定义为VIEW或公用表表达式(CTE)。如果您有许多这样的子查询,您可能会发现这样做更容易阅读和推理查询。
最后一个子查询用这种方法处理有点麻烦。我建议你先处理这个答案,然后再问另一个问题。
ssm49v7z2#
感谢@O.Jones,我找到了改进此查询的方法。
为了合并几个请求,我使用了如下CTE:
起始日期
结束日期
我已经将这个想法应用到不同的场景中,并制作了2个CTE。我不能合并所有的东西,有时候合并会导致成本增加。但是经过几次测试,我已经能够从7100的总成本增加到2100。
它仍然很多,但无论如何少了3倍。需要5秒钟而不是超时。
这是一个用于每月报告的查询,所以我不需要它是超级快,我会保持这种方式。
谢谢你!