为什么 SQL Where 子句值是由用户提供还是嵌入在代码中很重要?

Why does it matter whether a SQL Where clause value is provided by the user or embedded in the code matter?

我有一个按设计工作的遗留 SSRS 报告 - returns 大量数据。

我创建了它的一个推导,旨在使用特定值。

IOW,在旧报表中,该值由用户选择,而在派生报表中,它是 "baked in."

派生的报告,经过多次沙漏和仓鼠笼的嘎嘎声,终于举起双手说,"An error occurred during local report processing. The size necessary to buffer the XML content exceeded the buffer quota."

一个相关的问题是 here

两份报告的唯一区别是:

1) 我删除了其中一个参数

2) 在引用该参数的地方,我用文字值替换了 .rdl 中的代码。

为什么该更改会导致报告继续strike/go擅离职守?

更具体地说,以下是旧报告和派生报告之间的唯一区别:

1) 遗产:

<DataSetName>CPSData</DataSetName>

新:

<DataSetName>DataSetOldChicago</DataSetName>

2) 遗产:

<Value>=Parameters!Unit.value+", For Price Period: "+Parameters!BegDate.value+" - "+Parameters!EndDate.value</Value>

新:

<Value>="For Price Period: "+Parameters!BegDate.value+" - "+Parameters!EndDate.value</Value>

3) 遗产:

<DataSet Name="CPSData">
  <Query>
    <DataSourceName>CPSData</DataSourceName>
    <QueryParameters>
      <QueryParameter Name="@Unit">
        <Value>=Parameters!Unit.Value</Value>
      </QueryParameter>
      <QueryParameter Name="@BegDate">
        <Value>=Parameters!BegDate.Value</Value>
      </QueryParameter>
      <QueryParameter Name="@EndDate">
        <Value>=Parameters!EndDate.Value</Value>
      </QueryParameter>
      <QueryParameter Name="@SortBy">
        <Value>="Products"</Value>
      </QueryParameter>
    </QueryParameters>
    <CommandType>StoredProcedure</CommandType>
    <CommandText>sp_ViewPriceMatrix_Variance_RockBottom</CommandText>
    <rd:UseGenericDesigner>true</rd:UseGenericDesigner>
  </Query>

新:

<DataSet Name="DataSetOldChicago">
  <Query>
    <DataSourceName>CPSData</DataSourceName>
    <QueryParameters>
      <QueryParameter Name="@BegDate">
        <Value>=Parameters!BegDate.Value</Value>
      </QueryParameter>
      <QueryParameter Name="@EndDate">
        <Value>=Parameters!EndDate.Value</Value>
      </QueryParameter>
      <QueryParameter Name="@SortBy">
        <Value>=Parameters!SortBy.Value</Value>
      </QueryParameter>
    </QueryParameters>
    <CommandType>StoredProcedure</CommandType>
    <CommandText>ViewPriceMatrix_CraftworksRollup_OldChicago</CommandText>
  </Query>

出于某种原因,顺序略有不同 - 我不知道为什么会这样,但无法想象这会导致问题(字段列出的顺序)。

4) 遗产:

<DataSet Name="UnitDS">
  <Query>
    <DataSourceName>CPSData</DataSourceName>
    <CommandText>select Unit from MasterUnits order by Unit</CommandText>
    <rd:UseGenericDesigner>true</rd:UseGenericDesigner>
  </Query>
  <Fields>
    <Field Name="Unit">
      <DataField>Unit</DataField>
      <rd:TypeName>System.String</rd:TypeName>
    </Field>
  </Fields>
</DataSet>

新:

缺失,因为用户不再选择单位

5) 遗产:

<ReportParameter Name="Unit">
  <DataType>String</DataType>
  <AllowBlank>true</AllowBlank>
  <Prompt>Unit</Prompt>
  <ValidValues>
    <DataSetReference>
      <DataSetName>UnitDS</DataSetName>
      <ValueField>Unit</ValueField>
      <LabelField>Unit</LabelField>
    </DataSetReference>
  </ValidValues>
</ReportParameter>

新:

缺失 - 现在按字面提供。

6) 遗产:

[这里什么都没有]

新:

<ReportParameter Name="SortBy">
  <DataType>String</DataType>
  <Prompt>Sort By</Prompt>
</ReportParameter>

-- 所以 new/non-working 报告有这个 "SortBy" 参数,它是隐藏的并提供了一个默认值。但是另一个派生报告以这种方式设置了相同的参数,不会造成任何问题。

关于为什么这个问题会出现食人魔般的面貌,有什么想法吗?

更新

旧的(工作的)SP 和派生的(非工作的)SP 之间的区别是:

1)

旧:

ALTER Procedure [dbo].[sp_ViewPriceMatrix_Variance_test2]
    @Unit varchar(4000),
    @BegDate datetime,
    @EndDate datetime,
    @SortBy varchar(20) 

新:

IF OBJECT_ID ( 'ViewPriceMatrix_CraftworksRollup_OldChicago', 'P' ) IS NOT NULL   
    DROP PROCEDURE ViewPriceMatrix_CraftworksRollup_OldChicago;  
GO
CREATE PROCEDURE [dbo].[ViewPriceMatrix_CraftworksRollup_OldChicago]
    @BegDate datetime,
    @EndDate datetime

2)

旧:

where up.Unit = @Unit 

新:

where up.Unit = 'OLD CHICAGO'

3)

-同 2)

4)

旧:

Select @Statement = ('Update #TempContract Set [' + @PriceWeek  + ']=''' + IsNull(@Price,'0.00') + ''' where ItemCode=''' + @ItemCode + ''' and Unit=''' + @Unit + ''' and [ShortName]=''' + @ShortName +'''')

新:

Select @Statement = ('Update #TempContract Set [' + @PriceWeek  + ']=''' + IsNull(@Price,'0.00') + ''' where ItemCode=''' + @ItemCode + ''' and Unit=''''OLD CHICAGO'''' and [ShortName]=''' + @ShortName +'''')

5)

旧:

            fetch next from SetPriceWeekSQL into @PriceWeek, @BegDate
while @@fetch_status = 0
    begin
        SET @Week = @Week + 1 
        IF(@SQLstring='')
        Begin
            SET @SQLstring = @SQLstring + 'Insert Into #Temp Select Unit, ShortName, ItemCode, Description, regionorder, Contractprice, IsNull('+
            '['+@PriceWeek+'],''0.00'') as Price, (convert(decimal(10,3),''-0.001'')) as Variance, 
            '''+@PriceWeek+''' as PriceWeek, ''WK'+convert(varchar(2),@Week)+''' as Week From #TempContract'+@WherePriceWeek

            IF(@SortBy='Members')
            Begin
                SET @SQLstring = @SQLstring + ' UNION Select Unit, ShortName, '''', ''zzzz'', '''', '''', ''0'' as Price, ''-0.001'' as Variance, '''' as PriceWeek, ''WK'+convert(varchar(2),@Week)+''' as Week From #TempContract'+@WherePriceWeek
            End
            Else
            Begin
                SET @SQLstring = @SQLstring + ' UNION Select Unit, '''', ItemCode, Description, ''1000'', Contractprice, ''0'' as Price, ''-0.001'' as Variance, '''' as PriceWeek, ''WK'+convert(varchar(2),@Week)+''' as Week From #TempContract'+@WherePriceWeek
            End
        End
        ELSE 
        Begin
            SET @SQLstring = @SQLstring + ' UNION '
            SET @SQLstring = @SQLstring + 'Select Unit, ShortName, ItemCode, Description, regionorder, Contractprice, IsNull('+
            '['+@PriceWeek+'],''0.00'') as Price, IsNull(convert(decimal(10,2),['+@PriceWeek+'])-convert(decimal(10,2),['+@LastPriceWeek+']),''0.00'') as Variance, 
            '''+@PriceWeek+''' as PriceWeek, ''WK'+convert(varchar(2),@Week)+''' as Week From #TempContract'+@WherePriceWeek

            IF(@SortBy='Members')
            Begin
                SET @SQLstring = @SQLstring + ' UNION Select Unit, ShortName, '''', ''zzzz'', '''', '''', ''0'' as Price, ''0'' as Variance, '''' as PriceWeek, ''WK'+convert(varchar(2),@Week)+''' as Week From #TempContract Where IsNull(['+@LastPriceWeek+'],''0.00'') 
<> ''0.00'' or IsNull(['+@PriceWeek+'],''0.00'') <> ''0.00'' '
            End
            Else
            Begin
                SET @SQLstring = @SQLstring + ' UNION Select Unit, '''', ItemCode, Description, ''1000'', Contractprice, ''0'' as Price, ''0'' as Variance, '''' as PriceWeek, ''WK'+convert(varchar(2),@Week)+''' as Week From #TempContract Where IsNull(['+@LastPriceWeek+'],''0.00'') <> ''0.00'' or IsNull(['+@PriceWeek+'],''0.00'') <> ''0.00'' '
            End
        End

新:

fetch next from SetPriceWeekSQL into @PriceWeek, @BegDate
while @@fetch_status = 0
    begin
        SET @Week = @Week + 1 
        IF(@SQLstring='')
        Begin
            SET @SQLstring = @SQLstring + 'Insert Into #Temp Select Unit, ShortName, ItemCode, Description, regionorder, Contractprice, IsNull('+
            '['+@PriceWeek+'],''0.00'') as Price, (convert(decimal(10,3),''-0.001'')) as Variance, 
            '''+@PriceWeek+''' as PriceWeek, ''WK'+convert(varchar(2),@Week)+''' as Week From #TempContract'+@WherePriceWeek

                SET @SQLstring = @SQLstring + ' UNION Select Unit, '''', ItemCode, Description, ''1000'', Contractprice, ''0'' as Price, ''-0.001'' as Variance, '''' as PriceWeek, ''WK'+convert(varchar(2),@Week)+''' as Week From #TempContract'+@WherePriceWeek
        End
        ELSE 
        Begin
            SET @SQLstring = @SQLstring + ' UNION '
            SET @SQLstring = @SQLstring + 'Select Unit, ShortName, ItemCode, Description, regionorder, Contractprice, IsNull('+
            '['+@PriceWeek+'],''0.00'') as Price, IsNull(convert(decimal(10,2),['+@PriceWeek+'])-convert(decimal(10,2),['+@LastPriceWeek+']),''0.00'') as Variance, 
            '''+@PriceWeek+''' as PriceWeek, ''WK'+convert(varchar(2),@Week)+''' as Week From #TempContract'+@WherePriceWeek

                SET @SQLstring = @SQLstring + ' UNION Select Unit, '''', ItemCode, Description, ''1000'', Contractprice, ''0'' as Price, ''0'' as Variance, '''' as PriceWeek, ''WK'+convert(varchar(2),@Week)+''' as Week From #TempContract Where IsNull(['+@LastPriceWeek+'],''0.00'') <> ''0.00'' or IsNull(['+@PriceWeek+'],''0.00'') <> ''0.00'' '
        End
        SET @LastPriceWeek = @PriceWeek
        fetch next from SetPriceWeekSQL into @PriceWeek, @BegDate
    end

6)

旧:

IF(@SortBy='Members')
Begin
    Select 
        Unit,
        ShortName,
        ItemCode,
        Description,
        regionorder,
        Contractprice,
        convert(varchar(20),convert(decimal(10,2),Price)) as Price,
        sum(convert(money,Variance)) as Variance,
        VarianceAverage = convert(varchar(25),convert(decimal(10,2),(Select sum(convert(money,Variance)) From #Temp Where ShortName=T.ShortName and Week=T.Week) / Replace(((Select count(regionorder) From #Temp Where ShortName=T.ShortName and Week=T.Week)-count(
Variance)),'0','1'))), 
        PriceWeek,Week
    From #Temp T
    Group By
        Unit,
        ShortName,
        ItemCode,
        Description,
        regionorder,
        Contractprice,
        Price,
        PriceWeek,Week  
    Order By Week,ShortName,Description
End
ELSE
Begin
    Select 
        Unit,
        ShortName,
        ItemCode,
        Description,
        regionorder,
        Contractprice,
        convert(varchar(20),convert(decimal(10,2),Price)) as Price,
        sum(convert(money,Variance)) as Variance,
        VarianceAverage = convert(varchar(25),convert(decimal(10,2),(Select sum(convert(money,Variance)) From #Temp Where ItemCode=T.ItemCode and Week=T.Week) / Replace(((Select count(regionorder) From #Temp Where ItemCode=T.ItemCode and Week=T.Week)-count(Variance)),'0','1'))), 
        PriceWeek,Week
    From #Temp T 
    Group By
        Unit,
        ShortName,
        ItemCode,
        Description,
        regionorder,
        Contractprice,
        Price,
        PriceWeek,Week  
    Order By Week,Description,regionorder 
End

新:

 Select 
    Unit,
    ShortName,
    ItemCode,
    Description,
    regionorder,
    Contractprice,
    convert(varchar(20),convert(decimal(10,2),Price)) as Price,
    sum(convert(money,Variance)) as Variance,
    VarianceAverage = convert(varchar(25),convert(decimal(10,2),(Select sum(convert(money,Variance)) From #Temp Where ItemCode=T.ItemCode and Week=T.Week) / Replace(((Select count(regionorder) From #Temp Where ItemCode=T.ItemCode and Week=T.Week)-count(Variance)),'0','1'))), 
    PriceWeek,Week
From #Temp T 
Group By
    Unit,
    ShortName,
    ItemCode,
    Description,
    regionorder,
    Contractprice,
    Price,
    PriceWeek,Week  
Order By Week,Description,regionorder 

SQL 中的参数在确定特定语句的执行计划方面起着重要作用。例如,如果查询具有变量与硬编码文字,SQL 可能会为此创建两个完全不同的计划。 WHERE 子句中搜索参数的 addition/removal 也很可能会导致使用的索引发生更改。同样,如果一个计划已经使用了很长时间然后你改变了它,即使是轻微的改变,它现在也需要通过构建新计划、优化它、缓存它(如果可行)等的额外开销......

简而言之,这个看似很小的更改很可能完全改变了您的执行计划。就性能而言,这可能会产生各种意想不到的结果。我会推荐 运行 你的两个不同版本,所有输出 (PRINT/SELECTs) 都被删除(我希望这会降低内存使用率并允许你的第二个版本完成?)并看看你是否可以捕获实际执行计划。它可能会阐明它所做的不同之处,以及为什么它会突然停滞不前并最终失败。

您似乎在调用两个完全独立的存储过程 sp_ViewPriceMatrix_Variance_RockBottom 和 ViewPriceMatrix_CraftworksRollup_OldChicago。无论您在 SSRS 定义中进行了何种更改,您都需要查看基础数据查询之间的差异。我怀疑他们有很大的不同。