【问题标题】:Reduce Runtime of T-SQL Query减少 T-SQL 查询的运行时间
【发布时间】:2014-07-04 00:27:32
【问题描述】:

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

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

我编写了以下查询,但执行需要很长时间(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)

【问题讨论】:

  • 这些表上存在哪些索引?
  • 查询中引用的 every 列上的表别名也会非常有用(检查您的 where 子句)
  • 发布主查询的表索引和执行计划。
  • 为表拉取索引最有效的方法是什么?
  • 表格别名 - 你的意思是我应该确保添加到这样的; GI.SOLD_TO....

标签: sql performance tsql


【解决方案1】:

CTE 只是语法
我怀疑CTE被评估了很多次
使用 indexe(s) 将 CTE 实体化为 #temp,使其运行一次

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

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

where 否定左边,所以你可以做一个 join

另外,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
)

把它拉到连接中

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)

【讨论】:

  • 对于 CAST 日期,ACTUAL_PGI_DATE 是日期和时间,并填充时间,CALENDAR_DAY 也是日期时间,但所有时间都是 00:00:00.000,作为只读用户,我需要使用以下数据类型是,任何建议。
  • 如果我将 GI.SOLD_TO_CUSTOMER_ID 添加到 Customer 视图 Join 中,我是否应该将 GI.SOLD_TO_CUSTOMER_ID 留在 where 子句中?
  • 别动。很多时候,查询优化器足够聪明,可以及早过滤,但有时有很多连接它会错过它。
  • 如果两个日期时间都是 000 那么你应该不需要强制转换。不确定,但迄今为止的演员表可能意味着它不使用索引。
  • CTE 只是语法。 CTE 语法被插入/替换到查询中。该 cte 可能会被多次评估。如果它是#temp,则保证只运行一次。
猜你喜欢
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多