简体   繁体   English

SQL 查询运行缓慢 - 参数嗅探

[英]SQL query running slowly - parameter sniffing

I have a simple query where I return a list of orders by date range.我有一个简单的查询,我在其中按日期范围返回订单列表。 This query is used in a report which feeds it parameters(Site, From Date, and To Date).此查询用于为其提供参数(站点、起始日期和截止日期)的报告中。

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

The problem with this query is that it takes way too long and the problem lines are这个查询的问题是它花费的时间太长,问题行是

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

The format of the variable site is something like '09001' or '03001' where the left side is the company and the right side is the division变量站点的格式类似于“09001”或“03001”,其中左侧是公司,右侧是部门

Because when I run this query with hard-coded values, it runs pretty much instantaneously.因为当我使用硬编码值运行这个查询时,它几乎是即时运行的。 When I use the parameters, it takes minutes.当我使用参数时,它需要几分钟。

So I looked it up and I discovered about parameter sniffing.所以我查了一下,我发现了参数嗅探。 So I added the following line after the begin statement.所以我在 begin 语句之后添加了以下行。

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

However, it still runs extremely slow.但是,它仍然运行得很慢。

My new where statement would be我的新 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*

I also want the user to have the functionality of selecting all sites which will make the site variable be '00000' and thus it shouldn't run the company/division code check.我还希望用户具有选择所有站点的功能,这将使站点变量为“00000”,因此不应运行公司/部门代码检查。 This current where statement makes the query run very slow.当前的 where 语句使查询运行非常缓慢。

Does anyone know what I am doing wrong?有谁知道我做错了什么?

Can you try to avoid using LEFT() and RIGHT() by declaring few variables and assigning values to those variables and then using them in the SELECT statement?您能否通过声明几个变量并为这些变量赋值然后在 SELECT 语句中使用它们来避免使用 LEFT() 和 RIGHT() ?

a hint OPTIMIZED FOR UNKNOWN to avoid parameter sniffing:为 UNKNOWN 优化的提示,以避免参数嗅探:

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

Where p1 and p2 those two variables mentioned above其中 p1 和 p2 上面提到的这两个变量

I also want the user to have the functionality of selecting all sites which will make the site variable be '00000' and thus it shouldn't run the company/division code check.我还希望用户具有选择所有站点的功能,这将使站点变量为“00000”,因此不应运行公司/部门代码检查。 This current where statement makes the query run very slow.当前的 where 语句使查询运行非常缓慢。

This can be optimized by replacing current SELECT with IF statement that uses two SELECTs.这可以通过用使用两个SELECT 的 IF 语句替换当前的 SELECT 来优化。 If value is 00000 just avoid to check on company and division, else run the same select but with those extra checks如果值是 00000 只是避免检查公司和部门,否则运行相同的选择,但要进行额外的检查

Another striking thing is querying linked server objects with further join to local tables.另一个引人注目的事情是通过进一步连接到本地表来查询链接的服务器对象。 Consider to split this into a separate step, for instance by storing data in temporary table (not a table variable!) as intermediate result.考虑将其拆分为单独的步骤,例如将数据存储在临时表(不是表变量!)中作为中间结果。 Then temp table to be joined with local objects.然后临时表与本地对象连接。 This can improve accuracy of query plan because of better estimates.由于更好的估计,这可以提高查询计划的准确性。

Did you try taking left and right values of@site parameter in two different variables and using those variables in SP.您是否尝试在两个不同的变量中取@site 参数的左右值并在 SP 中使用这些变量。

For eg.例如。

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

Your where condition你的where条件

WHERE 
o.Company_Code = @compcode
AND o.Division_Code = @divcode

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM