1

我有一个简单的查询,按日期范围返回订单列表。此查询用于向其提供参数(站点、起始日期和截止日期)的报告中。

ALTER PROCEDURE [dbo].[Z_N_ECOM_ORDER_STATUS_DATERANGE]
    @Site VARCHAR(5),
    @FromDate DATETIME,
    @ToDate DATETIME
AS
BEGIN
    SET NOCOUNT ON;

    SELECT
        o.Company_Code,
        o.Division_Code,
        o.Control_Number,
        RTRIM(o.Customer_Purchase_Order_Number) AS Shopify_Num,
        CASE 
           WHEN p.PickTicket_Number IS NULL
              THEN i.PickTicket_Number 
              ELSE p.PickTicket_Number 
        END PickTicket_Number,
        i.Invoice_Number,
        o.Date_Entered,
        CASE
           WHEN ph.packslip IS NULL AND i.invoice_number IS NULL  
                AND P.pickticket_number IS NULL
              THEN 'Cancelled' 
           WHEN ph.packslip IS NULL AND i.invoice_number IS NULL 
                AND DATEADD(minute, 90, o.date_entered) > CURRENT_TIMESTAMP
              THEN 'Not Entered Yet'  
           WHEN ph.packslip IS NULL 
              THEN 'SHIPPED & UPLOADED' 
           ELSE RTRIM (z.status) 
        END Accellos_Status, 
        b.UPS_Tracking_Number Tracking_Number
    FROM
        [JMNYC-AMTDB].[AMTPLUS].[dbo].Orders o (nolock)
    LEFT JOIN
        [JMNYC-AMTDB].[AMTPLUS].[dbo].PickTickets p (nolock) ON o.Company_Code = p.Company_Code 
                                                         AND o.Division_Code = p.Division_Code 
                                                         AND o.Control_Number = p.Control_Number
    LEFT JOIN
        [JMNYC-AMTDB].[AMTPLUS].[dbo].Invoices i (nolock) ON o.Company_Code = i.Company_Code 
                                                      AND o.Division_Code = i.Division_Code 
                                                      AND o.Control_Number = i.Control_Number   
    LEFT JOIN
        [JMNYC-AMTDB].[AMTPLUS].[dbo].box b (nolock) ON o.Company_Code = b.Company_Code 
                                                AND o.Division_Code = b.Division_Code 
                                                AND i.PickTicket_Number = b.PickTicket_Number
    LEFT JOIN
        pickhead ph (nolock) ON p.PickTicket_Number = ph.packslip
    LEFT JOIN
        Z_Status z (nolock) ON ph.PROCSTEP = z.procstep
    WHERE 
        o.Company_Code = LEFT(@Site, 2)
        AND o.Division_Code = RIGHT(@Site, 3) 
        AND o.Customer_Number = 'ecom2x'
        AND o.Date_Entered BETWEEN @FromDate AND DATEADD(dayofyear, 1, @ToDate)
    ORDER BY 
        o.date_entered DESC
END

这个查询的问题是它花费的时间太长并且问题行是

 WHERE 
     o.Company_Code = LEFT(@Site, 2)
     AND o.Division_Code = RIGHT(@Site, 3)

变量站点的格式类似于“09001”或“03001”,其中左侧是公司,右侧是部门

因为当我使用硬编码值运行这个查询时,它几乎是瞬间运行的。当我使用参数时,它需要几分钟。

所以我查了一下,发现了参数嗅探。所以我在开始语句之后添加了以下行。

DECLARE @LocalSite VARCHAR(5) = CAST(@Site AS VARCHAR(5))

但是,它仍然运行非常缓慢。

我的新 where 语句将是

WHERE 
    o.Customer_Number = 'ecom2x'
    AND o.Date_Entered BETWEEN @FromDate AND DATEADD(dayofyear, 1,  @ToDate)
    AND ((@LocalSite = '00000') OR (O.Company_Code = LEFT(@LocalSite, 2) AND O.Division_Code = RIGHT(@LocalSite, 3))) 
order by o.date_entered desc*

我还希望用户具有选择所有站点的功能,这将使站点变量为“00000”,因此它不应该运行公司/部门代码检查。这个当前的 where 语句使查询运行非常缓慢。

有谁知道我做错了什么?

4

2 回答 2

0

您是否尝试在两个不同的变量中获取@site 参数的左右值,并在 SP 中使用这些变量。

例如。

Declare @compcode as varchar(2)
Declare @divcode as varchar(3)
Set @compcode=LEFT(@Site, 2)
Set @divcode=RIGHT(@Site, 3)

你的 where 条件

WHERE 
o.Company_Code = @compcode
AND o.Division_Code = @divcode
于 2019-01-25T20:39:41.533 回答
0

您是否可以通过声明几个变量并将值分配给这些变量然后在 SELECT 语句中使用它们来避免使用 LEFT() 和 RIGHT()?

提示 OPTIMIZED FOR UNKNOWN 以避免参数嗅探:

option (OPTIMIZE FOR (@p1 UNKNOWN, @p2 UNKNOWN))

其中 p1 和 p2 上面提到的这两个变量

我还希望用户具有选择所有站点的功能,这将使站点变量为“00000”,因此它不应该运行公司/部门代码检查。这个当前的 where 语句使查询运行非常缓慢。

这可以通过将当前 SELECT 替换为使用两个SELECT 的 IF 语句来优化。如果值为 00000,则避免检查公司和部门,否则运行相同的选择,但需要额外检查

另一个引人注目的事情是查询链接服务器对象并进一步连接到本地表。考虑将其拆分为一个单独的步骤,例如将数据存储在临时表(不是表变量!)中作为中间结果。然后将临时表与本地对象连接起来。由于更好的估计,这可以提高查询计划的准确性。

于 2019-01-25T19:58:25.730 回答