【问题标题】:SQL Unfixable parameter sniffing? Takes Seconds in SSMS, Minutes in SSRSSQL 不可修复的参数嗅探? SSMS 需要几秒钟,SSRS 需要几分钟
【发布时间】:2019-08-05 21:22:34
【问题描述】:

我有一份报告。查询需要几秒钟才能在 Microsoft SSMS (SQL Server Management Studio) 上运行,但每当我通过 Visual Studio 上的 SSRS 运行报告时,现在报告需要几分钟。我已经阅读了很多关于此的内容,每个人都说是它的参数嗅探,但我已经尝试了所有参数嗅探的解决方案,但它们似乎没有做任何事情。

起初,我将所有查询都放在存储过程中。然后,由于我认为将它们作为存储过程可能会导致速度变慢,因此我为报表创建了数据集,其中查询为文本形式。然而,这并没有解决问题。

这是我的查询,它有点长且复杂,但这不是这里的问题。是的,我知道这不是使用 nolock 的正确方法,但这就是我的雇主要求我使用 nolock 的方式。

SELECT DISTINCT 

DENSE_RANK() OVER (PARTITION BY O.Customer_Number ORDER BY O.Customer_Purchase_Order_Number ASC) 
    + DENSE_RANK() OVER (PARTITION BY O.Customer_Number ORDER BY O.Customer_Purchase_Order_Number DESC) 
         - 1 AS Total_Orders_Count

,COUNT(*) OVER () AS Total_Units_Count

 ,Sum(S.Retail  * OD.Quantity_Ordered) OVER (PARTITION BY O.Customer_Number) as Total_Net_Value

,Sum(OD.Price * OD.Quantity_Ordered) OVER (PARTITION BY O.Customer_Number) as Price
,Sum(OD.Discount_Value) OVER (PARTITION BY O.Customer_Number) as Discount_Value
,Sum(OD.Freight_Charges) OVER (PARTITION BY O.Customer_Number) as Freight_Charges
,Sum(OD.Tax_Value) OVER (PARTITION BY O.Customer_Number) as Tax_Value


,SUM(CASE WHEN O.Order_Status = '30' then 1 ELSE 0 END) OVER (PARTITION BY O.Customer_Number) as "Cancelled_Orders"
,SUM(CASE WHEN OD.Line_Status = '80' then 1 ELSE 0 END) OVER (PARTITION BY O.Customer_Number) as "Cancelled_Lines"
,Sum (T.Cost) OVER () Total_Product_Cost
,Avg (T.Cost) OVER () Avg_Product_Cost

FROM 
    [JMNYC-AMTDB].[AMTPLUS].[dbo].Orders O (nolock)

LEFT JOIN 
    [JMNYC-AMTDB].[AMTPLUS].[dbo].Order_Detail OD (nolock) On O.Company_Code =
        OD.Company_Code And O.Division_Code =
        OD.Division_Code And O.Control_Number =
        OD.Control_Number

LEFT JOIN
    [JMNYC-AMTDB].[AMTPLUS].[dbo].[Z_N_RetailPrices] S (nolock) On 
        OD.Item_Number = S.SKU

LEFT JOIN
    (
    Select
    T.Sku,
    CASE WHEN T.AvgCostActual is NULL THEN T.AvgCostStandard ELSE T.AvgCostActual END Cost

    From(
        Select distinct 

        Z.Sku, 
        AVG (CASE WHEN st.Actual_Cost <> 0 THEN st.Actual_Cost ELSE NULL END) OVER (PARTITION BY Z.Sku) AvgCostActual,
        AVG (CASE WHEN st.Standard_Cost <> 0 THEN st.Standard_Cost ELSE NULL END) OVER (PARTITION BY Z.Sku) AvgCostStandard
        From 

            [JMNYC-AMTDB].[AMTPLUS].[dbo].[Z_N_RetailPrices] Z

        LEFT JOIN

            [JMNYC-AMTDB].[AMTPLUS].[dbo].Style St (nolock) On 
            Z.Sku = St.Item_Number
        ) T  
    ) T on OD.Item_Number = T.Sku

WHERE 
    (O.Company_Code = @CompanyCode OR @CompanyCode IS NULL) AND 
    (O.Division_Code = @DivisionCode OR @DivisionCode IS NULL) AND
    o.Customer_Number = 'ecom2x' AND 
    ISNUMERIC(O.Customer_Purchase_Order_Number) <> 0 AND
    o.DateRecordModified BETWEEN @FromDate AND DATEADD(dayofyear, 1, @ToDate)

我可以在 MSSMS 中的查询之前添加它(因为如果我不通过 SSRS 选择参数,我需要声明参数)并且查询会在几秒钟内运行。

DECLARE @CompanyCode VARCHAR(5)
SET @CompanyCode = '03'

DECLARE @DivisionCode VARCHAR(5)
SET @DivisionCode = '001'

DECLARE @FromDate DATETIME
SET @FromDate = '2/1/2019'

DECLARE @ToDate DATETIME
SET @ToDate = '3/1/2019'

在 SSRS 中,使用相同的参数需要几分钟。

我尝试在我的 SSRS 查询中添加以下代码以加快速度(每个人都说这是参数嗅探的解决方案)

Declare @LocalCompanyCode NVARCHAR(5) = @CompanyCode
Declare @LocalDivisionCode NVARCHAR(5)= @DivisionCode
Declare @LocalToDate DATETIME= @ToDate
Declare @LocalFromDate DATETIME= @FromDate

然后更改我的 Where 子句以使用这些局部变量

WHERE 
    (O.Company_Code = @LocalCompanyCode OR @LocalCompanyCode IS NULL) AND 
    (O.Division_Code = @LocalDivisionCode OR @LocalDivisionCode IS NULL) AND
    o.Customer_Number = 'ecom2x' AND 
    ISNUMERIC(O.Customer_Purchase_Order_Number) <> 0 AND
    o.DateRecordModified BETWEEN @LocalFromDate AND DATEADD(dayofyear, 1,@LocalToDate)

但这改变了一切,查询仍然需要几分钟才能在 SSRS 中运行,而在 SSMS 中运行需要几秒钟。

我也尝试过使用 Recompile,同样的事情。

有人知道我能做什么吗?

【问题讨论】:

  • 您是否将数据库跨越到 JMNYC-AMTDB?如果您使用 JMNYC-AMTDB 作为您的数据源,则删除 refs 可能会更快。此外,您的 O.s 在 WHERE 中未大写,这可能会导致性能问题。
  • 在查看查询之前,我将在 Visual Studio 内的查询设计器中执行数据集。如果查询在那里运行得很快,它可能只是渲染时间。我有报告查询需要 15 秒,但渲染可能需要 5 分钟。如果报表在服务器上,您可以检查执行日志,但如果不只是在设计器中使用相同的参数运行查询并查看它运行的速度有多快。另一种选择,复制报告,删除所有显示数据并运行的报告项。您不会看到结果,但这意味着它只是在运行查询。

标签: sql sql-server reporting-services ssrs-2008 ssms


【解决方案1】:

您是否尝试过OPTIMIZE FOR 查询提示?例如。 OPTION (OPTIMIZE FOR (@LocalCompanyCode = 5, @LocalDivisionCode = 1)) --Choose representative examples of what values are normally used for the variables,它位于 where 子句之后,您可以根据需要指定任意数量的参数-值对,方法是用逗号分隔它们。当您不知道最佳值时,您也可以使用关键字 UNKNOWN,但这有时会导致次优计划

【讨论】:

  • 我可以试试。在公司代码和部门代码的几十种可能性中,我们只运行了其中大约 3 种。我可以针对多个参数对其进行优化吗?就像公司 9 部门 1 和公司 3 部门 1。我将这些代码行放在哪里?一直在我的 Declare @LocalCompanyCode 行上方?
  • @Natan - 我已更新我的答案以反映您的评论
  • 谢谢。那么这是多对的格式吗? (我不得不删除 @ 符号,StackOverflow 出现故障)(OPTIMIZE FOR (LocalCompanyCode = '09', LocalDivisionCode = '01'), (LocalCompanyCode = '03', LocalDivisionCode = '01') )我也应该这样使用 LocalCompanyCode 这是我声明的局部变量并将其分配为等于参数还是应该直接使用作为参数的 CompanyCode?​​span>
  • 抱歉我误解了第一个问题,每个参数只能指定一个值。您应该可以直接使用 CompanyCode 参数
【解决方案2】:

有人知道我能做什么吗?

  • SSRS 中的SET OPTIONS 与 SSMS 中的SET options 不同。考虑通过比较并在两个应用中启用相同的集合来使它们相等,因为它们的不匹配可能是导致性能差异的真正原因

  • 如果第一项没有带来任何改进,并且确实存在参数嗅探,请考虑在查询末尾添加OPTION (RECOMPILE)

可以使用以下方法检查 SET 选项:

DBCC USEROPTIONS

SSMS 中“SET 选项”的默认设置是:

SET quoted_identifier ON;   
SET arithabort ON;
SET SET ansi_null_dflt_on;  
SET ansi_warnings ON;   
SET ansi_padding ON;    
SET ansi_nulls ON;  
SET concat_null_yields_null ON;

要检查对查询的影响,可以在 SELECT 之前添加它们

【讨论】:

  • 你知道我在 SSRS 中找到(并更改了)设置选项吗?所以我应该让它们与 SSMS 中的相同?以下是 SSMS 的:[ textsize 2147483647 language us_english dateformat mdy datefirst 7 lock_timeout -1 quoted_identifier SET arithabort SET ansi_null_dflt_on SET ansi_warnings SET ansi_padding SET ansi_nulls SET concat_null_yields_null SET 隔离级别读取提交]
  • 调整了答案,这些选项可以在SSRS数据集中SELECT之前添加,使设置等于SSMS
  • 嘿@alexander,我有点困惑。在您的回答中,您说要在 select 语句之后添加它,但在您的评论中,您说要在之前添加它。哪一个是正确的,或者每个都做不同的事情?这真的会改变什么吗?我对设置选项一无所知,但它似乎可以处理警告或填充之类的事情?
  • “就在 SELECT 之前”。我相信,“Ahead”的意思是“before”;)但会调整答案以避免混淆
  • “我对设置选项一无所知,但它似乎可以处理警告或填充之类的事情?”。它们不会影响查询优化器和查询计划。一些晚上的阅读时间:dba.stackexchange.com/questions/9840/…sqlshack.com/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-17
  • 1970-01-01
相关资源
最近更新 更多