我正在尝试优化以下查询,根据执行计划,内部查询中的排序成本很高。可以重写以下查询,以便它易于阅读并且表现良好吗?
select
CL.col1, CL.col2
FROM
CLAIM CL WITH (NOLOCK)
INNER JOIN MEMBER MEM WITH (NOLOCK) ON MEM.MEMID=CL.MEMID
LEFT JOIN PAYVACATION PV WITH (NOLOCK) ON CL.CLAIMID = PV.CLAIMID
and pv.paymentid =
(select top 1 PAYVACATION.paymentid
from PAYVACATION WITH (NOLOCK),
payment WITH (NOLOCK)
where
payvoucher.claimid = cl.claimid
and PAYVACATION.paymentid = payment.paymentid
order by payment.paystatusdate desc)
答案 0 :(得分:1)
;WITH CTE AS
(
select CL.col1, CL.col2, cl.claimid
FROM CLAIM CL WITH (NOLOCK)
INNER JOIN MEMBER MEM WITH (NOLOCK) ON MEM.MEMID=CL.MEMID
LEFT JOIN PAYVACATION PV WITH (NOLOCK) ON CL.CLAIMID = PV.CLAIMID
),
CTE2 AS
(
select PAYVACATION.paymentid , PAYVACATION.claimid
,ROW_NUMBER() OVER (PARTITION BY PAYVACATION.claimid
ORDER BY payment.paystatusdate desc) rn
from PAYVACATION WITH (NOLOCK)
INNER JOIN payment WITH (NOLOCK) ON PAYVACATION.paymentid = payment.paymentid
INNER JOIN CTE WITH (NOLOCK) ON PAYVACATION.claimid = cl.claimid
)
SELECT CL.col1, CL.col2
FROM CTE CL
INNER JOIN CTE2 C2 ON C2.claimid = CL.claimid
AND C2.rn = 1
答案 1 :(得分:0)
假设payvoucher.claimid
实际上是指payvacation
表,您可以像这样格式化查询:
SELECT c.col1, c.col2
FROM claim c
INNER JOIN member m ON m.memid=c.memid
LEFT JOIN payvacation pv1 ON c.claimid = pv1.claimid
AND pv1.paymentid = (
SELECT TOP 1 pv2.paymentid
FROM payvacation pv2
INNER JOIN payment p ON pv2.paymentid = p.paymentid
WHERE pv2.claimid = cl.claimid
ORDER BY payment.paystatusdate DESC
)
但是,如果未从payvacation
表中选择任何列,则会忽略整个LEFT JOIN。如果确实从payvacation
表中选择了一列,那么在执行计划中确实会得到一个代价高昂的Sort运算符。为了消除它,我会创建一个索引视图,如下所示:
CREATE VIEW indexed_view
WITH SCHEMABINDING AS
SELECT pv.paymentid, pv.claimid, p.paystatusdate
FROM dbo.payvacation pv
INNER JOIN dbo.payment p ON pv.paymentid = p.paymentid
GO
CREATE UNIQUE CLUSTERED INDEX PK_indexed_view ON indexed_view (paymentid)
CREATE INDEX i2 ON indexed_view (claimid, paystatusdate) INCLUDE (paymentid)
然后使用NOEXPAND提示:
在子查询中使用索引视图SELECT c.col1, c.col2, pv1.paymentid
FROM claim c
INNER JOIN member m ON m.memid=c.memid
LEFT JOIN payvacation pv1 ON c.claimid = pv1.claimid
AND pv1.paymentid = (
SELECT TOP 1 iv.paymentid
FROM dbo.indexed_view iv WITH (NOEXPAND)
WHERE iv.claimid = c.claimid
ORDER BY iv.paystatusdate DESC
)
使用一些随机样本数据,第一次查询的查询成本为190.9,第二次查询的成本为4.96。
答案 2 :(得分:0)
在我们正确回答这个问题之前,您需要解决几件事情。
payvoucher.claimid
,您提供给我们的版本无法编译。我们可以猜到它应该是什么,但当事实证明是不同的时候,没有任何用处。(最后,摆脱NOLOCK
提示,或将其更改为同义词READUNCOMMITTED
并考虑一下,如果您仍然喜欢它们,就像现在一样;