【问题标题】:SET ROWCOUNT 1 performance issueSET ROWCOUNT 1 性能问题
【发布时间】:2014-05-06 14:20:04
【问题描述】:

我遇到了 SQL Server 2008 R2 的问题。如果我执行下面的语句,只需要不到 1 秒。

SELECT 
    A.REFERENCE_DATE AS REFERENCE_DATE
    ,A.MIS_BANK_ID AS BANK_ID
    ,'Unknown credit line' AS QUERY_LOG
    ,'STG_MIS_CREDIT_LINES_VALUE' AS [TABLE]
    ,'MIS_CREDIT_LINE_BRANCH_ID - MIS_CREDIT_LINE_ID' AS FIELD
    ,( 'MIS_CREDIT_LINE_BRANCH_ID: ' + A.MIS_CREDIT_LINE_BRANCH_ID + ' # MIS_CREDIT_LINE_ID: ' + A.MIS_CREDIT_LINE_ID ) AS [KEY]
    ,( A.MIS_CREDIT_LINE_BRANCH_ID + ' - ' + A.MIS_CREDIT_LINE_ID ) AS RESULT_1
    ,NULL AS RESULT_2
    ,NULL AS OUTSTANDING
FROM 
    STG_MIS_CREDIT_LINES_VALUE A
LEFT JOIN 
    STG_MIS_REG_CREDIT_LINES B ON A.REFERENCE_DATE = B.REFERENCE_DATE
                                  AND A.MIS_BANK_ID = B.MIS_BANK_ID
                                  AND A.MIS_CREDIT_LINE_BRANCH_ID = B.MIS_CREDIT_LINE_BRANCH_ID
                                  AND A.MIS_CREDIT_LINE_ID = B.MIS_CREDIT_LINE_ID
WHERE 
    B.MIS_CREDIT_LINE_ID IS NULL
    AND A.REFERENCE_DATE = '20131231'

当我在顶部添加“SET ROWCOUNT 1”语句时,执行需要超过 20 分钟!

SET ROWCOUNT 1

SELECT 
    A.REFERENCE_DATE AS REFERENCE_DATE
    ,A.MIS_BANK_ID AS BANK_ID
    ,'Unknown credit line' AS QUERY_LOG
    ,'STG_MIS_CREDIT_LINES_VALUE' AS [TABLE]
    ,'MIS_CREDIT_LINE_BRANCH_ID - MIS_CREDIT_LINE_ID' AS FIELD
    ,( 'MIS_CREDIT_LINE_BRANCH_ID: ' + A.MIS_CREDIT_LINE_BRANCH_ID + ' # MIS_CREDIT_LINE_ID: ' + A.MIS_CREDIT_LINE_ID ) AS [KEY]
    ,( A.MIS_CREDIT_LINE_BRANCH_ID + ' - ' + A.MIS_CREDIT_LINE_ID ) AS RESULT_1
    ,NULL AS RESULT_2
    ,NULL AS OUTSTANDING
FROM 
    STG_MIS_CREDIT_LINES_VALUE A
LEFT JOIN 
    STG_MIS_REG_CREDIT_LINES B ON A.REFERENCE_DATE = B.REFERENCE_DATE
                                  AND A.MIS_BANK_ID = B.MIS_BANK_ID
                                  AND A.MIS_CREDIT_LINE_BRANCH_ID = B.MIS_CREDIT_LINE_BRANCH_ID
                                  AND A.MIS_CREDIT_LINE_ID = B.MIS_CREDIT_LINE_ID
WHERE 
    B.MIS_CREDIT_LINE_ID IS NULL
    AND A.REFERENCE_DATE = '20131231'

如果我将 ROWCOUNT 参数更改为 2 或 0 或 100 或其他任何值,查询会再次快速运行(不到 1 秒)。

注意 1: 查询实际上返回 0 行(这对我来说没问题)。

注意 2: 我无法更改添加 TOP 1 语句的查询,因为我的是 ETL 软件,查询由固定的SET ROWCOUNT 1“组成”(出于技术原因,它是硬编码的)和企业用户编写的免费查询;像

SET ROWCOUNT 1

... SQL statement written by user ...

提前致谢。

尼古拉

[编辑]

执行计划(ROWCOUNT 1) http://pastebin.com/RambD7Aj

执行计划(ROWCOUNT 2) http://pastebin.com/cG4ngE4h

【问题讨论】:

  • 当 ROWCOUNT 为 1 时,您的索引似乎没有被命中。您能否获得两个查询的执行计划?
  • 添加了执行计划
  • 我注意到 SET ROWCOUNT 1 和 SET ROWCOUNT 2 之间的奇怪行为。执行计划完全改变了...... :/ pastebin.com/RambD7Aj pastebin.com/cG4ngE4h
  • 您发布的查询计划是估计计划。你认为你能掌握实际的计划吗?它将显示估计行数和实际行数之间的任何差异。您的第二个查询已经并行,可能是因为当您想要返回两行时,查询的成本最终超过了并行度的阈值。这导致了一个更快的计划,部分原因可能是因为它是并行的,但rowcount 1 查询不应该慢得多。对于预期返回 1 行的情况,应该有一个更快的计划。

标签: sql sql-server performance sql-server-2008-r2 rowcount


【解决方案1】:

如果不查看执行计划就无法确定,但听起来就像当您第一次添加 SET ROWCOUNT 1 时,它会尝试创建不使用索引的新执行计划,当您再次重新运行它时,它会使用正确的执行计划.

这里有几件事可以尝试。

  • 将OPTION (RECOMPILE) 添加到您的查询中。
  • 尝试将SET ROWCOUNT 1 替换为SELECT TOP 1
  • 查看两个查询的执行计划。
  • 添加ROW_NUMBER() 并使用 where 子句 where rn = 1 将查询转换为派生表

【讨论】:

  • 执行计划已添加,希望对您有所帮助
  • 我注意到 SET ROWCOUNT 1 和 SET ROWCOUNT 2 之间的奇怪行为。执行计划完全改变了...... :/ pastebin.com/RambD7Aj pastebin.com/cG4ngE4h
  • 你能在没有SET ROWCOUNT语句的情况下添加执行计划吗?
  • 基于一个计划使用散列连接这一事实,它暗示缺少索引或计划未选择正确的索引。还可以尝试添加OPTION MAXDOP(1) 来强制单线程,而不是尝试添加OPTION ( RECOMPILE, QUERYTRACEON 8649 ) 来强制多线程
  • 这里所有的执行计划:dl.dropboxusercontent.com/u/7161916/SQL/Execution_Plans.zip 我尝试在 SELECT 语句中添加一个 TOP 10000,然后还保留 SET ROWCOUNT 1(请参阅“TOP 10000.subplan”文件)。该行为与所有其他情况非常相似。唯一的“局外人”是 SET ROWCOUNT 1(参见“1.subplan”)。它让我发疯...... :(
猜你喜欢
  • 1970-01-01
  • 2017-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-01
  • 2018-02-24
  • 2022-01-23
  • 2018-05-12
相关资源
最近更新 更多