【问题标题】:Performance issue with larger resultsets MSSQL大型结果集 SQL 的性能问题
【发布时间】:2016-11-29 18:48:57
【问题描述】:

我目前在 MSSQL 中有一个存储过程,我根据给存储过程的变量多次执行 SELECT 语句。存储过程计算用户可以启用的每个过滤器将返回多少结果。 存储过程不是问题,我将 select 语句从 te 存储过程转换为常规的 select 语句,如下所示:

DECLARE @contentRootId int = 900589
DECLARE @RealtorIdList varchar(2000) = ';880;884;1000;881;885;'
DECLARE @publishSoldOrRentedSinceDate int = 8
DECLARE @isForSale BIT= 1
DECLARE @isForRent BIT= 0   
DECLARE @isResidential BIT= 1   
--...(another 55 variables)...

--Table to be returned
DECLARE @resultTable TABLE
(
    variableName varchar(100),
    [value] varchar(200)
)

-- Create table based of inputvariable. Example: turns ';18;118;' to a table containing two ints 18 AND 118 
DECLARE @RealtorIdTable table(RealtorId int) 
INSERT INTO @RealtorIdTable SELECT * FROM dbo.Split(@RealtorIdList,';') option (maxrecursion 150)

INSERT INTO @resultTable ([value], variableName) 
SELECT [Value], VariableName FROM( 
    Select count(*) as TotalCount, 
        ISNULL(SUM(CASE WHEN reps.ForRecreation = 1 THEN 1 else 0 end), 0) as ForRecreation,
        ISNULL(SUM(CASE WHEN reps.IsQualifiedForSeniors = 1 THEN 1 else 0 end), 0) as IsQualifiedForSeniors,
        --...(A whole bunch more SUM(CASE)...
    FROM TABLE1 reps
    LEFT JOIN temp t on
            t.ContentRootID = @contentRootId 
            AND t.RealEstatePropertyID = reps.ID
        WHERE 
            (EXISTS(select 1 from @RealtorIdTable where RealtorId = reps.RealtorID))
            AND (@SelectedGroupIds IS NULL OR EXISTS(select 1 from @SelectedGroupIdtable where GroupId = t.RealEstatePropertyGroupID))
            AND (ISNULL(reps.IsForSale,0) = ISNULL(@isForSale,0)) 
            AND (ISNULL(reps.IsForRent, 0) = ISNULL(@isForRent,0)) 
            AND (ISNULL(reps.IsResidential, 0) = ISNULL(@isResidential,0))  
            AND (ISNULL(reps.IsCommercial, 0) = ISNULL(@isCommercial,0))  
            AND (ISNULL(reps.IsInvestment, 0) = ISNULL(@isInvestment,0))  
            AND (ISNULL(reps.IsAgricultural, 0) = ISNULL(@isAgricultural,0))
            --...(Around 50 more of these WHERE-statements)...
            ) as tbl

    UNPIVOT ( 
        [Value]
        FOR [VariableName] IN(
        [TotalCount],
        [ForRecreation],
        [IsQualifiedForSeniors],
        --...(All the other things i selected in above query)...
        )
    ) as d

    select * from @resultTable

Realtor- 和 contentID 的组合为我提供了一组默认的 X 条记录。当我选择一个给我约 4600 条记录的组合时,执行时间约为 250 毫秒。当我使用给我〜600条记录的组合执行sattement时,执行时间约为20ms。

我想知道为什么会这样。我尝试删除选择中的所有 SUM(CASE,尝试从 WHERE 子句中删除几乎所有内容,并尝试删除 JOIN。但我一直看到 4600 和 600 的结果集之间存在巨大差异。

【问题讨论】:

  • 检查参数嗅探并添加OPTION(RECOMPILE)。您还可以更新表格上的统计信息。 BTW 请提供两种情况的执行计划
  • 我不确定您所说的“您还可以更新表格上的统计信息”是什么意思。我尝试了参数嗅探,它有帮助,但不是很多。我会检查选项(重新编译)
  • ISNULL(reps.IsForSale,0) = ISNULL(@isForSale,0) - 这些isnulls 也是问题。你最好改写成(@isforsale is null or isforsale=@isforsale)+重新编译
  • 更改 ISNULL 并没有多大作用。重新编译对较大的结果集没有任何作用,但会使较小的结果集变慢。
  • 为表和索引添加实际执行计划和DDL。

标签: sql-server performance tsql stored-procedures


【解决方案1】:

当记录数很大时,表变量的性能可能会更差。考虑改用临时表。见When should I use a table variable vs temporary table in sql server?

另外,考虑用替代 SQL 代码替换 UNPIVOT。编写自己的 TSQL 代码将为您提供更多控制权,甚至提高性能。参见例如PIVOT, UNPIVOT and performance

【讨论】:

  • 我已经尝试删除所有带有硬数据的表,但如果我这样做,查询不会更快。
  • 您可以在运行查询之前执行 SET STATISTICS TIME,IO ON 并上传输出吗?这将使我们了解性能问题的来源。
  • codepaste.net/efxenf 这是“消息”中显示的结果
  • 这不是完整的答案,它只包含链接。您可以下次使用 cmets(当您有足够的声誉时),或者使用代码 sn-ps 进行详细说明,而不仅仅是提供干燥的外部链接。在此处查看最佳实践:stackoverflow.com/help/how-to-answer
  • 我在统计输出中看到的是: 1. 考虑用@RealtorIdTable 变量上的INNER JOIN 替换WHERE 子句中的EXISTS。 2. 将 RealtorId 定义为 PRIMARY KEY。 3. 您还没有包含处理 RealEstatePropertySummaries 的查询部分,请注意,在该部分中您有两次 14905 的逻辑读取,这可能是相当多的。 4. 观察到 CPU 时间远低于经过的时间 (344 ms
猜你喜欢
  • 1970-01-01
  • 2019-06-29
  • 2013-11-23
  • 2022-06-16
  • 2023-04-05
  • 2021-01-05
  • 2011-08-05
  • 2012-01-24
  • 1970-01-01
相关资源
最近更新 更多