Sql server SQL Server查询需要性能改进-使用groupby汇总在临时表上进行左联接
我继承了一个巨大的查询/报表SP。它运行速度非常慢,扩展性不好。从它的书写方式来看,有很多左撇子的加入。它创建一个临时表,并将日期范围存储为datetime列中的各个日期,然后在此表上左键联接,以通过groupby/rollup从其他几个表获取信息,从而获取报告的总计。这是用我不熟悉的方式写的。我习惯于'WHERE'子句中的日期/参数,其中索引是一种优势 必须有更好的方法来做到这一点。也许只是一些明智的指导就好了。代码会更好。我一直在尝试通过CTE方法进行思考。有大量的ISNULL检查和嵌套转换来节省时间,只留下一个日期供比较,非常草率 我是新来的,所以我还不能告诉你关于DB的更多信息,比如索引,等等,我听说在需要索引的地方没有索引,等等。这个系统是几年前建立的,在SQL Server 2008上。无论如何,问题是:Sql server SQL Server查询需要性能改进-使用groupby汇总在临时表上进行左联接,sql-server,sql-server-2008,tsql,group-by,left-join,Sql Server,Sql Server 2008,Tsql,Group By,Left Join,我继承了一个巨大的查询/报表SP。它运行速度非常慢,扩展性不好。从它的书写方式来看,有很多左撇子的加入。它创建一个临时表,并将日期范围存储为datetime列中的各个日期,然后在此表上左键联接,以通过groupby/rollup从其他几个表获取信息,从而获取报告的总计。这是用我不熟悉的方式写的。我习惯于'WHERE'子句中的日期/参数,其中索引是一种优势 必须有更好的方法来做到这一点。也许只是一些明智的指导就好了。代码会更好。我一直在尝试通过CTE方法进行思考。有大量的ISNULL检查和嵌套转换
-- these are just sample dates as I have copied this from the SP into a query window since it's all dynamic sql and hard to read as just a red string.
DECLARE @FromDate date = '2015-06-01'
DECLARE @ToDate date = '2015-06-02'
DECLARE @TempDate date
DECLARE @TempToDate date
-- from here down is the SP
CREATE TABLE #SSTempDates (TempDate DATETIME)
IF @FromDate = ''
SET @TempDate = (SELECT CONVERT(NVARCHAR(10), MIN(ImportDate), 101) FROM OrdersViewWImport)
ELSE
SET @TempDate = @FromDate
IF @ToDate = ''
SET @TempToDate = (SELECT CONVERT(NVARCHAR(10),GETDATE(), 101))
ELSE
SET @TempToDate = @ToDate
WHILE @TempDate < @TempToDate
BEGIN
INSERT INTO #SSTempDates SELECT @TempDate
SET @TempDate = DATEADD(D,1,@TempDate)
END
-- done creating the temp table that holds the dates to join on
SELECT CASE WHEN GROUPING(CONVERT(NVARCHAR(10), TD.TempDate, 101)) = 1 THEN 'Total' ELSE CONVERT(NVARCHAR(10), TD.TempDate, 101) END AS [Date],
SUM(ISNULL(SH.QtyShipped,0)) AS [Units Shipped],
SUM(ISNULL(SH.ShippedPrice,0)) AS [Pounds Shipped],
SUM(ISNULL(C.QtyCancel,0)) AS [Units Cancelled],
SUM(ISNULL(C.CancelledPrice,0)) AS [Pounds Cancelled],
SUM(ISNULL(PR.OrdersPrinted,0)) AS [Allocated Orders],
SUM(ISNULL(SH.OrdersShipped,0)) + SUM(ISNULL(A.OrdersAssigned,0)) AS [Shipped Orders],
SUM(ISNULL(PR.QtyPrinted,0)) AS [Items Allocated],
SUM(ISNULL(SH.QtyShipped,0)) + SUM(ISNULL(A.QtyAssigned,0)) AS [Items Shipped],
CASE WHEN GROUPING(CONVERT(NVARCHAR(10), TD.TempDate, 101)) = 1 THEN
CASE WHEN ISNULL(SUM(PR.QtyPrinted),0) = 0 THEN 0
WHEN CAST(CONVERT(DECIMAL,(ISNULL(SUM(SH.QtyShipped),0) + ISNULL(SUM(A.QtyAssigned),0))) / CONVERT(DECIMAL,ISNULL(SUM(PR.QtyPrinted),0)) * 100 AS DECIMAL(19,2)) > 100 THEN 100
ELSE CAST(CONVERT(DECIMAL,(ISNULL(SUM(SH.QtyShipped),0) + ISNULL(SUM(A.QtyAssigned),0))) / CONVERT(DECIMAL,ISNULL(SUM(PR.QtyPrinted),0)) * 100 AS DECIMAL(19,2)) END
ELSE SUM(CASE WHEN ISNULL(PR.QtyPrinted,0) = 0 THEN 0
WHEN CAST(CONVERT(DECIMAL,(ISNULL(SH.QtyShipped,0) + ISNULL(A.QtyAssigned,0))) / CONVERT(DECIMAL,ISNULL(PR.QtyPrinted,0)) * 100 AS DECIMAL(19,2)) > 100 THEN 100
ELSE CAST(CONVERT(DECIMAL,(ISNULL(SH.QtyShipped,0) + ISNULL(A.QtyAssigned,0))) / CONVERT(DECIMAL,ISNULL(PR.QtyPrinted,0)) * 100 AS DECIMAL(19,2)) END) END AS [Fill Rate %],
CAST(CASE WHEN GROUPING(CONVERT(NVARCHAR(10), TD.TempDate, 101)) = 1 THEN ISNULL(SUM(NP.[ID]) / ISNULL((SUM(NP.[ID])+SUM(NP.[NG])+SUM(NP.[ZO])+SUM(NP.[SS])),0) * 100,0)
ELSE CASE WHEN SUM(NP.[ID]) = 0 THEN 0
ELSE ISNULL(SUM(NP.[ID]) / (SUM(NP.[ID])+SUM(NP.[NG])+SUM(NP.[ZO])+SUM(NP.[SS])) * 100,0) END END AS DECIMAL(19,2)) AS [Inv Disc %],
CAST(CASE WHEN GROUPING(CONVERT(NVARCHAR(10), TD.TempDate, 101)) = 1 THEN ISNULL(SUM(NP.[NG]) / ISNULL((SUM(NP.[ID])+SUM(NP.[NG])+SUM(NP.[ZO])+SUM(NP.[SS])),0) * 100,0)
ELSE CASE WHEN SUM(NP.[NG]) = 0 THEN 0
ELSE ISNULL(SUM(NP.[NG]) / (SUM(NP.[ID])+SUM(NP.[NG])+SUM(NP.[ZO])+SUM(NP.[SS])) * 100,0) END END AS DECIMAL(19,2)) AS [NG %],
CAST(CASE WHEN GROUPING(CONVERT(NVARCHAR(10), TD.TempDate, 101)) = 1 THEN ISNULL(SUM(NP.[SS]) / ISNULL((SUM(NP.[ID])+SUM(NP.[NG])+SUM(NP.[ZO])+SUM(NP.[SS])),0) * 100,0)
ELSE CASE WHEN SUM(NP.[SS]) = 0 THEN 0
ELSE ISNULL(SUM(NP.[SS]) / (SUM(NP.[ID])+SUM(NP.[NG])+SUM(NP.[ZO])+SUM(NP.[SS])) * 100,0) END END AS DECIMAL(19,2)) AS [SS %],
CAST(CASE WHEN GROUPING(CONVERT(NVARCHAR(10), TD.TempDate, 101)) = 1 THEN ISNULL(SUM(NP.[ZO]) / ISNULL((SUM(NP.[ID])+SUM(NP.[NG])+SUM(NP.[ZO])+SUM(NP.[SS])),0) * 100,0)
ELSE CASE WHEN SUM(NP.[ZO]) = 0 THEN 0
ELSE ISNULL(SUM(NP.[ZO]) / (SUM(NP.[ID])+SUM(NP.[NG])+SUM(NP.[ZO])+SUM(NP.[SS])) * 100,0) END END AS DECIMAL(19,2)) AS [ZO %],
CASE WHEN GROUPING(CONVERT(NVARCHAR(10), TD.TempDate, 101)) = 1
THEN CAST(AVG(CASE WHEN ISNULL(SH.AvgPrice,0) + ISNULL(A.AvgPrice,0) = 0 THEN 0 ELSE ISNULL(SH.AvgPrice,0) + ISNULL(A.AvgPrice,0) END) AS DECIMAL(19,2))
ELSE CAST(SUM(ISNULL(SH.AvgPrice,0)) + SUM(ISNULL(A.AvgPrice,0)) AS DECIMAL(19,2)) END AS [AOV],
CASE WHEN GROUPING(CONVERT(NVARCHAR(10), TD.TempDate, 101)) = 1
THEN CAST(AVG(CASE WHEN ISNULL(SH.AvgQty,0) + ISNULL(A.AvgQty,0) = 0 THEN 0 ELSE ISNULL(SH.AvgQty,0) + ISNULL(A.AvgQty,0) END) AS DECIMAL(19,2))
ELSE SUM(ISNULL(SH.AvgQty,0)) + SUM(ISNULL(A.AvgQty,0)) END AS [UPO]
FROM (SELECT DISTINCT TempDate FROM #SSTempDates) TD
LEFT JOIN (
SELECT COUNT(DISTINCT OrderNo) AS OrdersPrinted, SUM(Quantity) AS QtyPrinted, CONVERT(DATETIME,CONVERT(NVARCHAR, PrintBatch, 101)) AS PrintBatchDate
FROM PickTicketsOrders WITH (NOLOCK)
GROUP BY CONVERT(DATETIME,CONVERT(NVARCHAR, PrintBatch, 101))) PR ON PR.PrintBatchDate=CONVERT(NVARCHAR(10), TD.TempDate, 101)
LEFT JOIN (
SELECT COUNT(DISTINCT OI.OrderNo) AS OrdersShipped, SUM(OI.Quantity) AS [QtyShipped], SUM(OI.ExtPrice) AS ShippedPrice, CONVERT(DATETIME,CONVERT(NVARCHAR, S.ShipBatch, 101)) AS ShipDate,
CAST(AVG(OI.ExtPrice) AS DECIMAL(19,6)) AS AvgPrice, CAST(AVG(OI.Quantity) AS DECIMAL(19,6)) AS AvgQty
FROM Shipments S WITH (NOLOCK)
inner join (SELECT OrderNo, GroupNum, SUM(Quantity) AS Quantity, SUM(ExtPrice) AS ExtPrice FROM OrderItems GROUP BY OrderNo, GroupNum) OI ON OI.OrderNo = S.OrderNo AND OI.GroupNum = S.GroupNum
GROUP BY CONVERT(DATETIME,CONVERT(NVARCHAR, S.ShipBatch, 101))) SH ON SH.ShipDate=CONVERT(NVARCHAR(10), TD.TempDate, 101)
LEFT JOIN (
SELECT COUNT(DISTINCT OI.OrderNo) AS OrdersAssigned, SUM(OI.Quantity) AS [QtyAssigned], CONVERT(DATETIME,CONVERT(NVARCHAR, OA.ActDate, 101)) AS ActDate,
CAST(AVG(OI.ExtPrice) AS DECIMAL(19,6)) AS AvgPrice, CAST(AVG(OI.Quantity) AS DECIMAL(19,6)) AS AvgQty
FROM OrderActions OA WITH (NOLOCK)
INNER JOIN PndShipments P WITH (NOLOCK) ON P.OrderNo=OA.OrderNo AND P.GroupNum=OA.grouplinenum
INNER JOIN OrderItems OI WITH (NOLOCK) ON OI.OrderNo=P.OrderNo AND OI.GroupNum=P.GroupNum
INNER JOIN Orders O WITH (NOLOCK) ON O.OrderNo=OA.OrderNo
WHERE OA.Type=31
GROUP BY CONVERT(DATETIME,CONVERT(NVARCHAR, OA.ActDate, 101))) A ON A.ActDate=CONVERT(NVARCHAR(10), TD.TempDate, 101)
LEFT JOIN (
SELECT SUM(OI.Quantity) AS QtyCancel, SUM(OI.ExtPrice) AS CancelledPrice, CONVERT(DATETIME,CONVERT(NVARCHAR, CC.CancelDate, 101)) AS CancelDate
FROM OrderItems OI WITH (NOLOCK)
INNER JOIN Cancels CC WITH (NOLOCK) ON CC.OrderNo=OI.OrderNo AND CC.GroupNum=OI.GroupNum
GROUP BY CONVERT(DATETIME,CONVERT(NVARCHAR, CC.CancelDate, 101))) C ON C.CancelDate=CONVERT(NVARCHAR(10), TD.TempDate, 101)
LEFT JOIN (
SELECT CONVERT(DATETIME,CONVERT(NVARCHAR, PrintBatch, 101)) AS TotalNonPickDate,
SUM(CASE WHEN NoPickReason Like 'ID%' THEN 1.0 ELSE 0.0 END) AS [ID],
SUM(CASE WHEN NoPickReason Like 'NG%' THEN 1.0 ELSE 0.0 END) AS [NG],
SUM(CASE WHEN NoPickReason Like 'SS%' THEN 1.0 ELSE 0.0 END) AS [SS],
SUM(CASE WHEN NoPickReason Like 'ZO%' THEN 1.0 ELSE 0.0 END) AS [ZO]
FROM PickTickets WITH (NOLOCK)
WHERE PickBatch<>PrintBatch AND NoPickReason IN ('NG*','NG','ID*','ID','SS*','SS','ZO*','ZO')
GROUP BY CONVERT(DATETIME,CONVERT(NVARCHAR, PrintBatch, 101))) NP ON NP.TotalNonPickDate=CONVERT(NVARCHAR(10), TD.TempDate, 101)
WHERE (ISNULL(C.QtyCancel,0) > 0 OR ISNULL(PR.QtyPrinted,0) > 0 OR ISNULL(SH.QtyShipped,0) + ISNULL(A.QtyAssigned,0) > 0 OR
ISNULL(NP.[ID],0) > 0 OR ISNULL(NP.[NG],0) > 0 OR ISNULL(NP.[SS],0) > 0 OR ISNULL(NP.[ZO],0) > 0 )
GROUP BY CONVERT(NVARCHAR(10), TD.TempDate, 101) WITH ROLLUP ORDER BY [Date]
drop table #SSTempDates
首先,检查索引。 那么在以下情况下有太多的操作:
on, where
从中删除任何操作,如CONVERT、ISNULL、+等
让我们先看看加入
LEFT JOIN (
SELECT COUNT(DISTINCT OrderNo) AS OrdersPrinted, SUM(Quantity) AS QtyPrinted, CONVERT(DATETIME,CONVERT(NVARCHAR, PrintBatch, 101)) AS PrintBatchDate
FROM PickTicketsOrders WITH (NOLOCK)
GROUP BY CONVERT(DATETIME,CONVERT(NVARCHAR, PrintBatch, 101))) PR ON PR.PrintBatchDate=CONVERT(NVARCHAR(10), TD.TempDate, 101)
最好是写信
LEFT JOIN (
SELECT COUNT(DISTINCT OrderNo) AS OrdersPrinted, SUM(Quantity) AS QtyPrinted, CONVERT(DATETIME,CONVERT(NVARCHAR, PrintBatch, 101)) AS PrintBatchDate
, PrintBatch
FROM PickTicketsOrders WITH (NOLOCK)
GROUP BY CONVERT(DATETIME,CONVERT(NVARCHAR, PrintBatch, 101))) PR ON PR.PrintBatch=TD.TempDate
您的每个join都使用CONVERT。像我上面写的那样重写它
第二。看哪
每一个
ISNULLC.QtyCancel,0>0
会更好
C.QtyCancel>0
因为如果C.QtyCancel为null,那么C.QtyCancel>0也是false默认服务器设置,所以我们得到了相同的结果。
但函数ISNULL可能会破坏执行计划
另一件坏事在哪里
ISNULLSH.QtyShipped,0+ISNULLA.qtyAsigned,0>0
写起来很短,但会减慢查询速度
您的SQL太复杂了,您可能希望在没有任何示例数据的情况下在线处理它,也不清楚其用途。所有这些聚合和连接都足够可怕,但谁知道它们也可能是完全正确的。我也会想到CTE,而且这段代码看起来像是在尖叫交叉应用。是的,我没有发布任何数据,但谢谢。把每个派生表都放一个临时表,在每个临时表中都有一个日期。为什么需要在SELECT distinct TempDate中使用distinct?正如我前面所说,我继承了这一点,distinct是因为某些天没有数据,所以它不是在报告中有一个空行,而是从OrdersViewImport中选择可能没有连续日期的日期。有些日期可能不存在,有些日期有多行,因此DISTINCTwait,我的错,这只是循环将日期插入临时表中。。这真是浪费,谢谢你指出这一点谢谢你的输入,但正如我前面所述,CONVERT命令用于从datetime中删除时间,否则2015-01-01将类似于2015-01-01 11:25:24,并且日期比较将不起作用,因此我无法删除它们。我可以用DATEADDdd,DATEDIFFdd,0,xxxx,0来代替它们,但在测试中性能更差。是的,但这不是一个好方法。SQL server 2008是否具有日期数据类型?迄今为止的铸造应该更好。或者,在最坏的情况下,转换为yyyymmdd ISO格式,在这种情况下,执行DateDiff是首选方法。演员的想法我已经尝试过了,但是没有成功。此查询需要重写。我试图找到一个能从不同角度看到这一点的人,把大的查询变成几个小的查询。每个左撇子都加入。并对其进行评估。设置@DT=getdate;子查询打印日期diffms,@DT,getdate;