减少T-SQL查询的运行时间

时间:2021-12-17 12:43:47

-- WITH POD was causing the issue, removing this code reduced 2 year pull to 3 mins. Will post new question to figure out best way to include POD data.

- WITH POD导致问题,删除此代码减少2年拉3分钟。将发布新问题以找出包含POD数据的最佳方式。

--Edit for clarity, I am a read only user to these tables.

- 为清楚起见,我是这些表的只读用户。

I wrote the below query, but it takes a very long time to execute (20min). It is currently limited to 1 month, but user wants at least 1 year preferably 2. I assume this would scale time to hours. Can anyone take a look at let me know if there is a BKM I am not using to improve performance? Or if there is a better method for a report of this size? At 2 years, it would return ~100K rows from 17 tables.

我写了下面的查询,但执行需要很长时间(20分钟)。它目前仅限于1个月,但用户希望至少1年,最好是2年。我认为这会将时间缩短到数小时。任何人都可以看看,如果有一个BKM我不知道如何提高性能让我知道吗?或者,如果有更好的方法来获得这种规模的报告?在2年时,它将从17个表中返回~100K行。

WITH 

POD AS
(
SELECT SHIPMENTS.Delivery
  ,SHIPMENTS.Shipment_Number
  ,PROOF_OF_DELIVERY.Shipping_Carrier
  ,PROOF_OF_DELIVERY.Tracking_Number
  ,PROOF_OF_DELIVERY.Ship_Method
  ,PROOF_OF_DELIVERY.POD_Signature
  ,PROOF_OF_DELIVERY.POD_Date
  ,PROOF_OF_DELIVERY.POD_Time
FROM
SHIPMENTS 
LEFT JOIN PROOF_OF_DELIVERY
ON SHIPMENTS.Shipment_Number = PROOF_OF_DELIVERY.Delivery_Or_Shipment
WHERE Load_Date IN
(
SELECT MAX(Load_Date)
FROM PROOF_OF_DELIVERY
GROUP BY Delivery_Or_Shipment
)
)

SELECT DISTINCT GI.GOODS_ISSUE_DOCUMENT_ID
,GI.SALES_ORDER_ID
,GI.SALES_ORDER_LINE_ID
,GI.SALES_ORDER_TYPE_CODE
,GI.DELIVERY_HEADER_ID
,GI.DELIVERY_ITEM_ID
,FD.FISCAL_MONTH_CODE
,GI.MATERIAL_NUMBER
,GI.SHIPPED_QTY
,SO.ORDERER_NAME
,SO.CREATED_BY
,SO.CONTACT_PERSON
,GI.SOLD_TO_CUSTOMER_ID
,GI.SHIP_TO_CUSTOMER_ID
,GI.ORIGINAL_COMMIT_DATE
,GI.SHIP_FROM_PLANT_ID
,GI.ACTUAL_PGI_DATE
,GI.CUSTOMER_PO_NUMBER
,GI.SHIPPED_PRICE
,(GI.SHIPPED_PRICE * GI.SHIPPED_QTY) AS EXT_SHIPPED_PRICE
,GI.SALES_ORGANIZATION_CODE
,GI.DELIVERY_NOTE_PRIORITY_CODE
,FD.FISCAL_WEEK_CODE
,DV.DIVISION_CODE
,DN.Delivery_Item_Creation_Date
,SOLD.CUSTOMER_SHORT_NAME AS SOLD_TO_CUSTOMER_SHORT_NAME
,SHIP.CUSTOMER_SHORT_NAME AS SHIP_TO_CUSTOMER_SHORT_NAME
,SHIP.Customer_Site_Name
,SHIP.REGION_NAME
,MATD.MATERIAL_DESCRIPTION
,MATD.STANDARD_COST
,(MATD.STANDARD_COST * GI.SHIPPED_QTY) AS EXT_STANDARD_COST
,MATD.GLOBAL_EVENT
,PLT.LEAD_TIME_FOR_ORIGINAL_COMMIT
,OPRM.BASE_PART_CODE
,MATD.PRODUCT_INSP_MEMO
,MATD.MATERIAL_PRICING_GROUP_CODE
,MATD.MATERIAL_STATUS AS MMPP
,PIM.PIM_PBG_GROUPING
,SOL.SHIPPING_CONDITION
,SVO.SERVICE_ORDER_NUM 
,SO.CREATION_TIME AS SO_CREATION_TIME
,SOL.CREATED_TIME AS SO_LINE_CREATED_TIME
,SOL.SHIPPING_POINT
,SDT.SALES_DOCUMENT_TYPE_CODE AS SVO_DOCUMENT_TYPE_CODE
,EQU.EQUIPMENT_NUM
,EQU.SERIAL_NUMBER
,EQU.CUSTOMERTOOLID
,POD.Shipment_Number
,POD.Shipping_Carrier
,POD.Tracking_Number
,POD.Ship_Method
,POD.POD_Signature
,POD.POD_Date
,POD.POD_Time
,DATEDIFF(dd,SO.CREATION_TIME,GI.ACTUAL_PGI_DATE) AS Cycle_Time_to_PGI_Days   
,DATEDIFF(hh,SO.CREATION_TIME,GI.ACTUAL_PGI_DATE) AS Cycle_Time_to_PGI_Hours  

FROM GOODS_ISSUE AS GI
INNER JOIN dbo.Delivery_Notes AS DN
ON GI.DELIVERY_HEADER_ID = DN.DELIVERY_HEADER_CODE AND GI.DELIVERY_ITEM_ID = DN.DELIVERY_ITEM_CODE
INNER JOIN dbo.Customer_View AS SOLD
ON GI.SOLD_TO_CUSTOMER_ID = SOLD.CUSTOMER_CODE
INNER JOIN dbo.Customer_View AS SHIP
ON GI.SOLD_TO_CUSTOMER_ID = SHIP.CUSTOMER_CODE
INNER JOIN dbo.MATERIAL_DETAILS AS MATD
ON GI.MATERIAL_NUMBER = MATD.MATERIAL_NUMBER
INNER JOIN dbo.OPR_MATERIAL_DIM AS OPRM
ON OPRM.MATERIAL_NUMBER = GI.MATERIAL_NUMBER
LEFT JOIN dbo.SM_DATE_DIM AS FD
ON CAST(FD.CALENDAR_DAY AS DATE) = CAST(GI.ACTUAL_PGI_DATE AS DATE)
LEFT JOIN dbo.DIM_PUBLISHED_LEAD_TIME_COMMIT AS PLT
ON PLT.MATERIAL_NUMBER = OPRM.BASE_PART_CODE
LEFT JOIN dbo.PRODUCT_INSP_MEMO_DIM AS PIM
ON PIM.PRODUCT_INSP_MEMO = MATD.PRODUCT_INSP_MEMO
INNER JOIN  dbo.SM_SALES_ORDER_LINE_FACT AS SOL
ON SOL.SALES_ORDER_CODE = GI.SALES_ORDER_ID AND SOL.SALES_ORDER_LINE_CODE = GI.SALES_ORDER_LINE_ID
INNER JOIN dbo.SM_SALES_ORDER_FACT AS SO
ON SO.SALES_ORDER_CODE = GI.SALES_ORDER_ID
INNER JOIN dbo.SM_DIVISION_DIM AS DV
ON SO.DIVISION_SID = DV.DIVISION_SID
LEFT JOIN dbo.SERVICE_ORDER_FACT AS SVO
ON SVO.SERVICE_ORDER_NUM = SO.SERVICE_ORDER_NUMBER
LEFT JOIN dbo.SM_SALES_DOCUMENT_TYPE_DIM AS SDT
ON SDT.SALES_DOCUMENT_TYPE_SID = SVO.SALES_DOCUMENT_TYPE_SID
LEFT JOIN dbo.SM_EQUIPMENT_DIM AS EQU
ON EQU.EQUIPMENT_SID = SVO.EQUIPMENT_SID
LEFT JOIN POD
ON POD.Delivery = GI.DELIVERY_HEADER_ID


WHERE GI.ACTUAL_PGI_DATE > GETDATE()-32
AND SOLD_TO_CUSTOMER_ID IN (0010000252,0010000898,0010001121,0010001409,0010001842,0010001852,0010001879,0010001977,0010001978,0010002021,0010002202,0010002227,0010002982,0010003118,0010003176,0010003294,0010005492,0010006904,0010007048,0010007080,0010010381,0010010572,0010010905,0010011999,0010012014,0010012048,0010012571,0010013124,0010013711,0010013713,0010013824,0010014180,0010014188,0010014333,0010015059,0010015313,0010015414,0010015541,0010015544,0010015550)

1 个解决方案

#1


3  

A CTE is just syntax
I suspect that CTE is evaluated many times
Materialze the CTE to #temp with indexe(s) so it is run once

CTE只是语法我怀疑CTE被多次评估将CTE物化为带有索引的#temp,因此它运行一次

This cast will hurt it
Make those columns true dates and index them

这个演员会伤害它使这些列真实日期并索引它们

ON CAST(FD.CALENDAR_DAY AS DATE) = CAST(GI.ACTUAL_PGI_DATE AS DATE)

That where negates the left so you can just do a join

在那里否定左边所以你可以加入

Also that MAX(Load_Date) could match on another shipment

此外,MAX(Load_Date)可以匹配另一批货物

SELECT SHIPMENTS.Delivery
  ,SHIPMENTS.Shipment_Number
  ,PROOF_OF_DELIVERY.Shipping_Carrier
  ,PROOF_OF_DELIVERY.Tracking_Number
  ,PROOF_OF_DELIVERY.Ship_Method
  ,PROOF_OF_DELIVERY.POD_Signature
  ,PROOF_OF_DELIVERY.POD_Date
  ,PROOF_OF_DELIVERY.POD_Time
 FROM SHIPMENTS 
 JOIN PROOF_OF_DELIVERY
   ON SHIPMENTS.Shipment_Number = PROOF_OF_DELIVERY.Delivery_Or_Shipment
WHERE PROOF_OF_DELIVERY.Load_Date IN
(
    SELECT MAX(Load_Date)
    FROM PROOF_OF_DELIVERY
    GROUP BY Delivery_Or_Shipment
)

Pull this up into the join

将其拉入连接

INNER JOIN dbo.Customer_View AS SOLD
  ON GI.SOLD_TO_CUSTOMER_ID = SOLD.CUSTOMER_CODE 
 AND GI.SOLD_TO_CUSTOMER_ID IN (0010000252,0010000898,0010001121,0010001409,0010001842,0010001852,0010001879,0010001977,0010001978,0010002021,0010002202,0010002227,0010002982,0010003118,0010003176,0010003294,0010005492,0010006904,0010007048,0010007080,0010010381,0010010572,0010010905,0010011999,0010012014,0010012048,0010012571,0010013124,0010013711,0010013713,0010013824,0010014180,0010014188,0010014333,0010015059,0010015313,0010015414,0010015541,0010015544,0010015550)

#1


3  

A CTE is just syntax
I suspect that CTE is evaluated many times
Materialze the CTE to #temp with indexe(s) so it is run once

CTE只是语法我怀疑CTE被多次评估将CTE物化为带有索引的#temp,因此它运行一次

This cast will hurt it
Make those columns true dates and index them

这个演员会伤害它使这些列真实日期并索引它们

ON CAST(FD.CALENDAR_DAY AS DATE) = CAST(GI.ACTUAL_PGI_DATE AS DATE)

That where negates the left so you can just do a join

在那里否定左边所以你可以加入

Also that MAX(Load_Date) could match on another shipment

此外,MAX(Load_Date)可以匹配另一批货物

SELECT SHIPMENTS.Delivery
  ,SHIPMENTS.Shipment_Number
  ,PROOF_OF_DELIVERY.Shipping_Carrier
  ,PROOF_OF_DELIVERY.Tracking_Number
  ,PROOF_OF_DELIVERY.Ship_Method
  ,PROOF_OF_DELIVERY.POD_Signature
  ,PROOF_OF_DELIVERY.POD_Date
  ,PROOF_OF_DELIVERY.POD_Time
 FROM SHIPMENTS 
 JOIN PROOF_OF_DELIVERY
   ON SHIPMENTS.Shipment_Number = PROOF_OF_DELIVERY.Delivery_Or_Shipment
WHERE PROOF_OF_DELIVERY.Load_Date IN
(
    SELECT MAX(Load_Date)
    FROM PROOF_OF_DELIVERY
    GROUP BY Delivery_Or_Shipment
)

Pull this up into the join

将其拉入连接

INNER JOIN dbo.Customer_View AS SOLD
  ON GI.SOLD_TO_CUSTOMER_ID = SOLD.CUSTOMER_CODE 
 AND GI.SOLD_TO_CUSTOMER_ID IN (0010000252,0010000898,0010001121,0010001409,0010001842,0010001852,0010001879,0010001977,0010001978,0010002021,0010002202,0010002227,0010002982,0010003118,0010003176,0010003294,0010005492,0010006904,0010007048,0010007080,0010010381,0010010572,0010010905,0010011999,0010012014,0010012048,0010012571,0010013124,0010013711,0010013713,0010013824,0010014180,0010014188,0010014333,0010015059,0010015313,0010015414,0010015541,0010015544,0010015550)