我们有一个Transact-SQL查询,其中包含where部分中的子查询。内部连接会多次添加tOrderDetails字段的不必要结果,因此我们采用(性能较差)子查询。它经常超时。我们需要相同的结果,但性能更好。有什么建议吗?
SELECT sum (cast(Replace(tOrders.TotalCharges,'$','') as money)) as TotalCharges
FROM [ArtistShare].[dbo].tOrders
WHERE tOrders.isGiftCardRedemption = 0
and tOrders.isTestOrder=0
and tOrders.LastDateUpdate between @startDate and @endDate
and (SELECT count(tORderDetails.ID)
from tORderDetails
where tORderDetails.ORderID = tORders.ORderID
and tOrderDetails.isPromo=1) = 0
and (SELECT top 1 tProjects.ProjectReleaseDt
from tProjects JOIN tOrderDetails
on tOrderDetails.ProjectID = tProjects.ID
where tOrderDetails.OrderID = tOrders.OrderID) >= @startDate
答案 0 :(得分:4)
如果您只想知道至少有一个存在或不存在,为什么要统计记录?
SELECT Sum (Cast(Replace(tOrders.TotalCharges, '$', '') AS MONEY)) AS TotalCharges
FROM [ArtistShare].[dbo].tOrders
WHERE tOrders.isGiftCardRedemption = 0
AND tOrders.isTestOrder = 0
AND tOrders.LastDateUpdate BETWEEN @startDate AND @endDate
AND NOT EXISTS
(
SELECT 1 FROM tORderDetails
WHERE tORderDetails.ORderID = tORders.ORderID
AND tOrderDetails.isPromo = 1 )
AND EXISTS
(
SELECT 1 FROM tProjects INNER JOIN tOrderDetails
ON tOrderDetails.ProjectID = tProjects.ID
WHERE tOrderDetails.OrderID = tOrders.OrderID
AND tProjects.ProjectReleaseDt >= @startDate )
答案 1 :(得分:2)
虽然我认为EXISTS
可能表现最佳,但您也可以考虑采用以下方法。当您在问题中提到您的查询“多次添加tOrderDetails字段的不必要结果”时,可能是因为您有多个tOrderDetail记录,因此您需要使用GROUP BY
折叠它们。不是使用效率非常低的相关子查询,而是使用像INNER JOIN
这样的单个子查询。
SELECT
sum (cast(Replace(tOrders.TotalCharges, '$', '') as money)) as TotalCharges
FROM [ArtistShare].[dbo].tOrders
INNER JOIN (
SELECT OrderID
FROM tOrderDetails d INNER JOIN tProjects p on d.ProjectID = p.ID
WHERE d.isPromo = 0 AND p.ProjectReleaseDt > @startDate
GROUP BY OrderID
) qualifyingOrders ON qualifyingOrders.OrderID = tOrders.OrderID
WHERE tOrders.isGiftCardRedemption = 0
and tOrders.isTestOrder=0
and tOrders.LastDateUpdate between @startDate and @endDate
同样,你应该将它与 EXISTS 方法进行比较,看看哪一个表现更好,并且对你想要达到的目标最有意义。
答案 2 :(得分:0)
您可以尝试的另一种方法是先将您的子查询数据放入临时表中,然后查询这些数据。
显然,我没有完全掌握您的数据或理解数据关系,但希望以下示例可以帮助您找到满足您需求的正确查询。
值得至少比较一下表现。
DECLARE @ORDERDETAILS TABLE
(
INT idCount,
INT orderId
)
INSERT INTO
@ORDERDETAILS
SELECT
COUNT(tORderDetails.ID),
tORderDetails.ORderID
WHERE
tOrderDetails.isPromo = 1
GROUP BY
tORderDetails.ORderID
DECLARE @PROJECTS TABLE
(
DATETIME releaseDte,
INT orderId
)
INSERT INTO
@PROJECTS
SELECT
tProjects.ProjectReleaseDt,
tOrderDetails.OrderID
FROM
tProjects JOIN tOrderDetails ON tOrderDetails.ProjectID = tProjects.ID
SELECT
sum (cast(Replace(tOrders.TotalCharges,'$','') as money)) as TotalCharges
FROM
[ArtistShare].[dbo].tOrders JOIN @ORDERDETAILS ON @ORDERDETAILS.orderId = tORders.ORderID
JOIN @PROJECTS ON @PROJECTS.orderId = tOrders.OrderID)
WHERE tOrders.isGiftCardRedemption = 0
and tOrders.isTestOrder=0
and tOrders.LastDateUpdate between @startDate and @endDate
AND @ORDERDETAILS.idCount = 0
--and (SELECT count(tORderDetails.ID)
-- from tORderDetails
-- where tORderDetails.ORderID = tORders.ORderID
-- and tOrderDetails.isPromo=1) = 0
AND @PROJECTS.releaseDte >= @startDate --NOT QUITE SURE WHAT THIS EXACTLY MIMICS WHAT YOU ARE TRYING TO DO BUT IF NOT YOU COULD REMOVE THE JOIN AND SUB-QUERY AS FOLLOWS
--AND (SELECT TOP 1 @PROJECTS.releaseDte WHERE PROJECTS.orderId = tOrders.OrderID) >= @startDate
--and (SELECT top 1 tProjects.ProjectReleaseDt
-- from tProjects JOIN tOrderDetails
-- on tOrderDetails.ProjectID = tProjects.ID
-- where tOrderDetails.OrderID = tOrders.OrderID) >= @startDate