我有两个问题。
第一部分是关于我在下面做的速度。我正在获取数据集并获取每个DISTINCT
,然后加入一个与标准相加/计数的子查询,然后重复这五次。在第一个LEFT JOIN
之后我的运行时间为02秒,在第二个LEFT JOIN
之后我的运行时间为04秒,但在第三个LEFT JOIN
上运行时间为44秒。如果将该查询拉到一边并单独运行,则仅为01秒。完成查询的总运行时间为70秒。
第一部分问题:
在第三次加入时,是什么让这个查询显着变慢?
第二部分:我确信我以低效的方式完成了这项工作。我环顾了一会儿,无法找到一种方法来完成我正在做的事情,同时仍然能够为每个子查询设置不同的标准。
第二部分问题:
有没有更好的方法来完成此查询?
用户1413评论后编辑。
开始时 SELECT DISTINCT
在SQL Server执行计划视图中显示49%的成本。我更改了SELECT DISTINCT
正在选择的表格,我的运行时间降到了01秒以下。
SELECT DISTINCT
od.location, currentTires, currentAlignments, currentLubes,
currentBatteries,currentSiping,currentCarcount
FROM
comm.dbo.ordetail as od
LEFT JOIN
(SELECT
od2.location, SUM(od2.qty_shipped) as currentTires
FROM
comm.dbo.ordetail as od2
JOIN
comm.dbo.invmas as invmas2 ON invmas2.item_num = od2.item#
JOIN
comm.dbo.ordhrd as oh2 ON oh2.location = od2.location
AND oh2.inv_date = od2.inv_date
AND oh2.invoice# = od2.invoice#
WHERE
(oh2.type_of_rec = '01' OR oh2.type_of_rec = '02')
AND od2.inv_date >= '2017-02-01 00:00:00.000'
AND od2.inv_date <= '2017-02-28 00:00:00.000'
AND ( invmas2.category = 'uhp' OR invmas2.category = 'tour' OR invmas2.category = 'mass' OR invmas2.category = 'suv' OR invmas2.category = 'ltat' OR invmas2.category = 'ltmt' OR invmas2.category = 'lthwy' OR invmas2.category = 'snow' OR invmas2.category = 'stdls' )
GROUP BY
od2.location) as currentTires ON od.location = currentTires.location
LEFT JOIN
(SELECT
od3.location, SUM(od3.qty_shipped) as currentAlignments
FROM
comm.dbo.ordetail as od3
JOIN
comm.dbo.invmas as invmas3 ON invmas3.item_num = od3.item#
JOIN
comm.dbo.ordhrd as oh3 ON oh3.location = od3.location
AND oh3.inv_date = od3.inv_date
AND oh3.invoice# = od3.invoice#
WHERE
(oh3.type_of_rec = '01' OR oh3.type_of_rec = '02')
AND od3.inv_date >= '2017-02-01 00:00:00.000'
AND od3.inv_date <= '2017-02-28 00:00:00.000'
AND (od3.item# = '8501' OR od3.item# = '8502')
GROUP BY
od3.location) as currentAlignments ON od.location = currentAlignments.location
LEFT JOIN
(SELECT
od4.location, SUM(od4.qty_shipped) as currentLubes
FROM
comm.dbo.ordetail as od4
JOIN
comm.dbo.invmas as invmas4 ON invmas4.item_num = od4.item#
JOIN
comm.dbo.ordhrd as oh4 ON oh4.location = od4.location
AND oh4.inv_date = od4.inv_date
AND oh4.invoice# = od4.invoice#
WHERE
(oh4.type_of_rec = '01' OR oh4.type_of_rec = '02')
AND od4.inv_date >= '2017-02-01 00:00:00.000'
AND od4.inv_date <= '2017-02-28 00:00:00.000'
AND (od4.item# = '200fs' OR od4.item# = '200c' OR od4.item# = '200m' OR od4.item# = '200s')
GROUP BY
od4.location) as currentLubes ON od.location = currentLubes.location
LEFT JOIN ( SELECT od5.location,SUM(od5.qty_shipped) as currentBatteries
FROM comm.dbo.ordetail as od5
JOIN comm.dbo.invmas as invmas5
ON invmas5.item_num = od5.item#
JOIN comm.dbo.ordhrd as oh5
ON oh5.location = od5.location
AND oh5.inv_date = od5.inv_date
AND oh5.invoice# = od5.invoice#
WHERE ( oh5.type_of_rec = '01' OR oh5.type_of_rec = '02' )
AND od5.inv_date >= '2017-02-01 00:00:00.000'
AND od5.inv_date <= '2017-02-28 00:00:00.000'
AND invmas5.manufact = 'inter'
GROUP BY od5.location) as currentBatteries
ON od.location = currentBatteries.location
LEFT JOIN ( SELECT od6.location,SUM(od6.qty_shipped) as currentSiping
FROM comm.dbo.ordetail as od6
JOIN comm.dbo.invmas as invmas6
ON invmas6.item_num = od6.item#
JOIN comm.dbo.ordhrd as oh6
ON oh6.location = od6.location
AND oh6.inv_date = od6.inv_date
AND oh6.invoice# = od6.invoice#
WHERE ( oh6.type_of_rec = '01' OR oh6.type_of_rec = '02' )
AND od6.inv_date >= '2017-02-01 00:00:00.000'
AND od6.inv_date <= '2017-02-28 00:00:00.000'
AND invmas6.manufact = 'inter'
GROUP BY od6.location) as currentSiping
ON od.location = currentSiping.location
LEFT JOIN ( SELECT od7.location,COUNT(DISTINCT oh7.invoice#) as currentCarcount
FROM comm.dbo.ordetail as od7
JOIN comm.dbo.ordhrd as oh7
ON oh7.location = od7.location
AND oh7.inv_date = od7.inv_date
AND oh7.invoice# = od7.invoice#
WHERE ( oh7.type_of_rec = '01' OR oh7.type_of_rec = '02' )
AND od7.inv_date >= '2017-02-01 00:00:00.000'
AND od7.inv_date <= '2017-02-28 00:00:00.000'
AND oh7.veh_make != ''
AND od7.item# != ''
GROUP BY od7.location) as currentCarcount
ON od.location = currentCarcount.location
ORDER BY od.location
示例数据输出:
答案 0 :(得分:2)
这里可以做很多事情。对于初学者,下面的以下连接之一可以被删除,因为od5和od6都返回相同的项目。
LEFT JOIN ( SELECT od5.location,SUM(od5.qty_shipped) as currentBatteries
FROM comm.dbo.ordetail as od5
JOIN comm.dbo.invmas as invmas5
ON invmas5.item_num = od5.item#
JOIN comm.dbo.ordhrd as oh5
ON oh5.location = od5.location
AND oh5.inv_date = od5.inv_date
AND oh5.invoice# = od5.invoice#
WHERE ( oh5.type_of_rec = '01' OR oh5.type_of_rec = '02' )
AND od5.inv_date >= '2017-02-01 00:00:00.000'
AND od5.inv_date <= '2017-02-28 00:00:00.000'
AND invmas5.manufact = 'inter'
GROUP BY od5.location) as currentBatteries
ON od.location = currentBatteries.location
LEFT JOIN ( SELECT od6.location,SUM(od6.qty_shipped) as currentSiping
FROM comm.dbo.ordetail as od6
JOIN comm.dbo.invmas as invmas6
ON invmas6.item_num = od6.item#
JOIN comm.dbo.ordhrd as oh6
ON oh6.location = od6.location
AND oh6.inv_date = od6.inv_date
AND oh6.invoice# = od6.invoice#
WHERE ( oh6.type_of_rec = '01' OR oh6.type_of_rec = '02' )
AND od6.inv_date >= '2017-02-01 00:00:00.000'
AND od6.inv_date <= '2017-02-28 00:00:00.000'
AND invmas6.manufact = 'inter'
GROUP BY od6.location) as currentSiping
ON od.location = currentSiping.location
至于性能和可读性,请尝试以下内容。注意:我无法对此进行测试,但是,它可能会让有更多时间来调整查询性能的人深入了解。
DECLARE @LowDate DATETIME = '2017-02-01 00:00:00.000'
DECLARE @HighDate DATETIME = '2017-02-28 00:00:00.000'
SELECT
DetailList.location,
currentTires = SUM(currentTires),
currentAlignments = SUM(currentAlignments),
currentLubes = SUM(currentLubes),
currentBatteries = SUM(currentBatteries),
currentSiping = SUM(currentSiping),
carCount = SUM(hasCar)
FROM
(
SELECT
od.location,
currentLubes=CASE WHEN ( od.item# = '200fs' OR od.item# = '200c' OR od.item# = '200m' OR od.item# = '200s' ) THEN od.qty_shipped ELSE NULL END,
currentAlignments=CASE WHEN ( od.item# = '8501' OR od.item# = '8502' ) THEN od.qty_shipped ELSE NULL END,
currentSiping = CASE WHEN ( invmas.item_num = 'p15' OR invmas.item_num = 'u15' ) THEN od.qty_shipped ELSE NULL END,
currentBatteries = CASE WHEN invmas.manufact = 'inter' THEN od.qty_shipped ELSE NULL END,
currentTires= CASE WHEN ( invmas.category = 'uhp' OR invmas.category = 'tour' OR invmas.category = 'mass' OR invmas.category = 'suv' OR invmas.category = 'ltat' OR
invmas.category = 'ltmt' OR invmas.category = 'lthwy' OR invmas.category = 'snow' OR invmas.category = 'stdls' ) THEN od.qty_shipped ELSE NULL END,
hasCar= CASE WHEN (oh.veh_make != '' AND od.item# !='') THEN 1 ELSE 0 END
FROM
comm.dbo.ordetail as od
LEFT JOIN comm.dbo.invmas as invmas ON invmas.item_num = od.item# --FOR currentCarcount
INNER JOIN comm.dbo.ordhrd as oh ON oh.location = od.location AND oh.inv_date = od.inv_date AND oh.invoice# = od.invoice#
WHERE
od.inv_date BETWEEN '2017-02-01 00:00:00.000' AND '2017-02-28 00:00:00.000'
AND
oh.type_of_rec IN('01','02')
)AS DetailList
GROUP BY
DetailList.location