【问题标题】:Performance issue with SQL QuerySQL 查询的性能问题
【发布时间】:2019-11-05 17:26:05
【问题描述】:

我从两个表(预测和订单)中提取数据来计算销售预测的准确性。

我正在采取的步骤:

  1. 确定产品-区域-需求月份的所有详尽组合 b/w 两个数据集...我们称之为 (1)

  2. 在预测数据中识别不同的预测快照...我们称之为 (2)

  3. 执行 (1) 和 (2) 的交叉连接...我们称之为 (3)

  4. 对订单和预测的 (3) 行执行等效的“SUMIF()”。例如,如果我将 2 月份的预测订单与实际订单进行比较,

1 月“INDPOR”预测---> 对于某些产品/地区-2 月交付组合:2 月预测(1 月生成)与 1 月 1 日之后预订且交付计划在 2 月的订单

2 月“INDPOR”预测--->对于相同的产品/地区-2 月交货日期组合:2 月预测(2 月生成)与 1 月 27 日*之后预订的订单* 2 月交货时间表

注 1:为同一月份生成多个预测

注 2:使用的会计日历定义;这就是为什么 2 月从 1 月 27 日开始

输出正确生成。但是,它非常缓慢(1小时+)。请帮助我对其进行微调并使其更快,因为我也需要将其用于更大的数据集。

其他细节:

  1. 我正在从我的桌面本地在 SQL Server 2014 上运行此程序。使用 SQL 数据导入向导将其从 Excel 文件中上传到 SQL 中
  2. 输入预测数据:ForecastAggTable
  3. 输入订单数据:OrderAggTable

Input and Output Files

代码:

Select * 
from
    (

            Select *,

            (Select isnull(sum([Forecast Qty]),0) from ForecastAggTable t2 where t2.LOB=D.LOB and
                    t2.[Demand Month]=D.[Demand Month] and t2.Class=D.Class 
                    and t2.[Item Type]=D.[Item Type] and t2.[LoB Region]=D.[LoB Region] and
                    t2.[Key Account]=D.[Key Account] and t2.Country=D.Country 
                    and t2.[Master Customer]=D.[Master Customer] and t2.[INDPOR Version]=D.[INDPOR Version])[Forecast Qty],

            (
                    Select isnull(sum([Order Qty]),0) from OrderAggTable t1 where t1.LOB=D.LOB and
                    t1.[SAD Month]=D.[Demand Month] and t1.Class=D.Class 
                    and t1.[Item Type]=D.[Item Type] and t1.[LoB Region]=D.[LoB Region] and
                    t1.[Key Account]=D.[Key Account] and t1.Country=D.Country 
                    and t1.[Master Customer]=D.[Master Customer] and t1.[Book Date]>=D.[INDPOR Timestamp]
            )[SAD-OrderQty],

            (
                    Select isnull(sum([Order Revenue]),0) from OrderAggTable t1 where t1.LOB=D.LOB and
                    t1.[SAD Month]=D.[Demand Month] and t1.Class=D.Class 
                    and t1.[Item Type]=D.[Item Type] and t1.[LoB Region]=D.[LoB Region] and
                    t1.[Key Account]=D.[Key Account] and t1.Country=D.Country 
                    and t1.[Master Customer]=D.[Master Customer] and t1.[Book Date]>=D.[INDPOR Timestamp]
            )[SAD-OrderRevenue],


            (
                    Select isnull(sum([Order Qty]),0) from OrderAggTable t1 where t1.LOB=D.LOB and
                    t1.[RDD Month]=D.[Demand Month] and t1.Class=D.Class 
                    and t1.[Item Type]=D.[Item Type] and t1.[LoB Region]=D.[LoB Region] and
                    t1.[Key Account]=D.[Key Account] and t1.Country=D.Country 
                    and t1.[Master Customer]=D.[Master Customer] and t1.[Book Date]>=D.[INDPOR Timestamp]
            )[RDD-OrderQty],

            (
                    Select isnull(sum([Order Revenue]),0) from OrderAggTable t1 where t1.LOB=D.LOB and
                    t1.[RDD Month]=D.[Demand Month] and t1.Class=D.Class 
                    and t1.[Item Type]=D.[Item Type] and t1.[LoB Region]=D.[LoB Region] and
                    t1.[Key Account]=D.[Key Account] and t1.Country=D.Country 
                    and t1.[Master Customer]=D.[Master Customer] and t1.[Book Date]>=D.[INDPOR Timestamp]
            )[RDD-OrderRevenue]


            from
            (
            Select distinct LOB,[INDPOR Version],[INDPOR Timestamp],[Demand Month],
            [Demand Quarter],[Min Date],Class,[Item Type],[Offer PF],
            [LoB Region],[Key Account],Country,[Master Customer]

            from

            (

                            Select V.LOB,V.[SAD Month][Demand Month],V.[SAD Quarter][Demand Quarter],V.[SAD Min Date][Min Date],V.Class,
                            [Item Type],[Offer PF],[LoB Region],[Key Account],Country,[Master Customer]
                            from OrderAggTable V

                            union

                            (
                            Select Z.LOB,Z.[RDD Month][Demand Month],Z.[RDD Quarter][Demand Quarter],Z.[RDD Min Date][Min Date],Z.Class,
                            [Item Type],[Offer PF],[LoB Region],[Key Account],Country,[Master Customer]
                            from OrderAggTable Z
                            )

                            union

                            (
                            Select LOB,[Demand Month],[Demand Quarter],[Min Date],Class[Class],[Item Type],[Offer PF],[LoB Region],
                            [Key Account],Country,[Master Customer] from ForecastAggTable
                            )
            )A

            cross join

            (
            select distinct [INDPOR Version],[INDPOR Timestamp] 
            from ForecastAggTable
            )B
            )D
            where [Min Date]>=[INDPOR Timestamp]
            )E
            where ([SAD-OrderQty] +  [RDD-OrderQty] + [Forecast Qty]<>0)

【问题讨论】:

  • SSMS 查询分析器告诉你什么?
  • 执行计划 通常是开始调查性能问题的好地方。请参阅paste the plan,了解在您的问题中包含执行计划的方法。
  • 同意 cmets 关于查看执行计划以调试性能。此外,您在 select 子句中有 5 个子选择。每一个都将在结果集的每一行执行一次。因此,如果您有 1000 行,则子选择将执行 5 * 1000 次。这可能会导致性能问题。如果需要且可能,请尝试重写该结果并可能将中间结果存储在表 var 中。此外,联合的 select 语句没有 where 子句,请确保这是您想要的,因为您将提取完整的表。最后,&这是为了可维护性,将 select * 替换为列列表。
  • 对每个表中的记录数有了一些了解,为我们提供了从哪里开始的线索。 distinctunion(与 union all 相比)也是昂贵的操作 - 确保这是您真正想要的。
  • 实际查询运行大约需要 5 个小时。我根据前 100,000 名(选择前 100,000 名 *)得到的图表是否代表所需的努力?仍在运行完整的查询。

标签: sql sql-server database tsql


【解决方案1】:

如何简化并减少表格的传递次数。

在本例中,我对预测表进行两次扫描,一次用于不同的,一次用于联合,一次扫描订单表。

with cte as
(
 select distinct [INDPOR Version],[INDPOR Timestamp] 
            from ForecastAggTable
)
,cte2 as
(
Select 
    V.LOB
    ,iif(DUP=0,V.[SAD Month]    ,V.[RDD Month]      )   [Demand Month]
    ,iif(DUP=0,V.[SAD Quarter]  ,V.[RDD Quarter]    )   [Demand Quarter]
    ,iif(DUP=0,V.[SAD Min Date] ,V.[RDD Min Date]   )   [Min Date]
    ,V.[Book Date]
    ,V.Class
    ,V.[Item Type]
    ,V.[Offer PF]
    ,V.[LoB Region]
    ,V.[Key Account]
    ,V.Country
    ,V.[Master Customer]
    ,null [INDPOR Version]
    ,null [Forecast Qty]
    ,iif(DUP=0,v.[Order Qty]    ,null   )       [SAD-OrderQty]
    ,iif(DUP=0,V.[Order Revenue]    ,null   )   [SAD-OrderRevenue]
    ,iif(DUP=1,V.[Order Qty]    ,null   )       [RDD-OrderQty]
    ,iif(DUP=1,V.[Order Revenue]    ,null   )   [RDD-OrderRevenue]
from OrderAggTable V
cross join (select dup from (values (0),(1))a(dup)) a
union all
Select 
    LOB
    ,[Demand Month]
    ,[Demand Quarter]
    ,[Min Date]
    ,[Min Date]
    ,Class
    ,[Item Type]
    ,[Offer PF]
    ,[LoB Region]
    ,[Key Account]
    ,Country
    ,[Master Customer] 
    ,[INDPOR Version]
    ,[Forecast Qty] 
    ,null[SAD-OrderQty]
    ,null[SAD-OrderRevenue]
    ,null[RDD-OrderQty]
    ,null[RDD-OrderRevenue]
    from ForecastAggTable
)
select
    cte2.LOB
    ,cte.[INDPOR Version]
    ,cte.[INDPOR Timestamp]
    ,cte2.[Demand Month]
    ,cte2.[Demand Quarter]
    ,cte2.[Min Date]
    ,cte2.Class
    ,cte2.[Item Type]
    ,cte2.[Offer PF]
    ,cte2.[LoB Region]
    ,cte2.[Key Account]
    ,cte2.Country
    ,cte2.[Master Customer]
    ,isnull(sum(cte2.[Forecast Qty]    ),0) [Forecast Qty]     
    ,isnull(sum(cte2.[SAD-OrderQty]    ),0) [SAD-OrderQty]
    ,isnull(sum(cte2.[SAD-OrderRevenue])    ,0) [SAD-OrderRevenue]
    ,isnull(sum(cte2.[RDD-OrderQty]    ),0) [RDD-OrderQty]     
    ,isnull(sum(cte2.[RDD-OrderRevenue])    ,0) [RDD-OrderRevenue]
from cte2
inner join cte
on cte2.[Book Date]>=cte.[INDPOR Timestamp]
where isnull(cte2.[INDPOR Version],cte.[INDPOR Version])=cte.[INDPOR Version]
group by    
     cte2.LOB
    ,cte2.[Demand Month]
    ,cte2.[Demand Quarter]
    ,cte2.[Min Date]
    ,cte2.Class
    ,cte2.[Item Type]
    ,cte2.[Offer PF]
    ,cte2.[LoB Region]
    ,cte2.[Key Account]
    ,cte2.Country
    ,cte2.[Master Customer]
    ,cte.[INDPOR Version]
    ,cte.[INDPOR Timestamp]
having 
    isnull(sum(cte2.[Forecast Qty]     ),0) + 
    isnull(sum(cte2.[SAD-OrderQty]     ),0) +
    isnull(sum(cte2.[RDD-OrderQty]     ),0) 
    !=0

【讨论】:

  • "cross join (select dup from (values (0),(1))a(dup))"....这段代码中的 DUP 到底发生了什么?我不确定我是否理解这个逻辑?
  • 谢谢您,先生。这就像一个魅力。我现在似乎更好地理解了这个查询。但是,您能否解释以下行:“where isnull(cte2.[INDPOR Version],cte.[INDPOR Version])=cte.[INDPOR Version]” 似乎无法想象或弄清楚这对逻辑的影响.
猜你喜欢
  • 2013-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-08
  • 2011-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多