我有一个简单的查询,该查询按日期范围返回订单列表。该查询在报表中使用,该报表为其提供参数(“站点”,“起始日期”和“截止日期”)。
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”,其中左侧是公司,右侧是部门
因为当我使用硬编码值运行此查询时,它几乎立即运行。使用参数时,需要花费几分钟。
所以我查了一下,发现了参数嗅探。因此,我在begin语句之后添加了以下行。
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语句使查询运行非常缓慢。
有人知道我在做什么错吗?
答案 0 :(得分:0)
您可以尝试通过声明几个变量并为这些变量分配值,然后在SELECT语句中使用它们来避免使用LEFT()和RIGHT()吗?
为未知而优化的提示以避免参数嗅探:
option (OPTIMIZE FOR (@p1 UNKNOWN, @p2 UNKNOWN))
其中p1和p2是上述两个变量
我还希望用户具有选择所有站点的功能 这将使站点变量为“ 00000”,因此不应运行 公司/部门代码检查。当前的where语句使得 查询运行非常慢。
可以通过将当前的SELECT替换为使用两个 SELECT的IF语句来进行优化。如果值为00000,则避免检查公司和部门,否则运行相同的选择,但要进行额外的检查
另一个引人注目的事情是查询链接的服务器对象,并进一步连接到本地表。考虑将其分为一个单独的步骤,例如,通过将数据存储在临时表(而不是表变量!)中作为中间结果。然后将临时表与本地对象连接。由于估算值更好,因此可以提高查询计划的准确性。
答案 1 :(得分:0)
您尝试在两个不同的变量中获取@site参数的左值和右值,并在SP中使用这些变量。
例如。
Declare @compcode as varchar(2)
Declare @divcode as varchar(3)
Set @compcode=LEFT(@Site, 2)
Set @divcode=RIGHT(@Site, 3)
您的条件
WHERE
o.Company_Code = @compcode
AND o.Division_Code = @divcode