使用 TOP 1
逻辑消除 WHERE
子句中的记录的最有效方法是什么?
表tblQuoteStatusChangeLog
不在JOIN
中。
但根据此表中的值,我需要消除 NewQuoteStatusID
= 12
它的工作方式是这样的,但我正在寻找更有效的方法,因为我的排序(前 N 排序)运算符过于广泛。
SELECT
Q.ControlNo
,sum(fid.amtbilled) as Premium
FROM
[dbo].tblQuotes Q
inner join [dbo].[tblFin_Invoices] FI on Q.QuoteID = FI.QuoteID and FI.failed = 0
inner join [dbo].[tblFin_InvoiceDetails] FID on FI.[InvoiceNum] = FID.InvoiceNum
WHERE (
SELECT TOP 1 NewQuoteStatusID
FROM tblQuoteStatusChangeLog
WHERE (ControlNo = Q.ControlNo)
ORDER BY Timestamp DESC
) <> 12
Group by
Q.ControlNo
最佳答案
您的代码是RBAR ;一次执行同一个子查询1,效率非常低。
您担心“排序”,但这本身并不是问题。进一步查看平面图的上方和左侧;到嵌套循环。看到顶部的胖输入线和下面的瘦输入线。基本上你已经多次命中你的类别了。
建议:尝试使用基于集合的解决方案。 “提前”“准备”WHERE 子句所需的数据,这样就可以消除 RBAR。想象一下,您有 LatestStatus
作为一个包含 ControlNo
和 StatusID
列的表。应用过滤器会简单得多;查询优化器应该能够找到更有效的整体计划。
您可以使用 CTE 进行设置。
;with StatusByControlNo as (
SELECT ROW_NUMBER() OVER(PARTITION BY ControlNo ORDER BY Timestamp DESC) AS RowNo,
ControlNo, Timestamp, NewQuoteStatusID
FROM tblQuoteStatusChangeLog
) ...
/*Easy to get Latest status per ControlNo from here*/
SELECT ControlNo, NewQuoteStatusID
FROM StatusByControlNo
WHERE RowNo = 1
现在,经过一些调整,您的查询将变为:
;with StatusByControlNo as (
SELECT ROW_NUMBER() OVER(PARTITION BY ControlNo ORDER BY Timestamp DESC) AS RowNo,
ControlNo, Timestamp, NewQuoteStatusID
FROM tblQuoteStatusChangeLog
)
SELECT
Q.ControlNo,
sum(fid.amtbilled) as Premium
FROM
tblQuotes Q
inner join tblFin_Invoices FI
on Q.QuoteID = FI.QuoteID and FI.failed = 0
inner join tblFin_InvoiceDetails FID
on FI.InvoiceNum = FID.InvoiceNum
inner join StatusByControlNo S
on S.ControlNo = Q.ControlNo and S.RowNo = 1
WHERE
S.ControlNo <> 12
Group by Q.ControlNo
不用说,您可以尝试对此的多种变体。但核心原则是减少 RBAR 并寻找更加“基于集合”的解决方案。
关于sql-server - 如何过滤 WHERE 子句中的 TOP 1 条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52670185/