【问题标题】:SqlCommand.Cancel() causes a performance boost?SqlCommand.Cancel() 导致性能提升?
【发布时间】:2011-03-31 04:15:11
【问题描述】:

我已经看到这出现在代码中的几个地方,从来没有解释,只是在它上面的一个神秘的注释(声明和执行包括上下文的想法。它只是一个运行 SqlCommand 的标准过程):

//SqlCommand cmd = new SqlCommand();
//cmd.ExecuteReader();
//Read off the results

//Cancel the command. This improves query time.
cmd.Cancel ();

基本上,在完成查询后,它会返回并取消它,声称性能有所提升。我想你可能会在它释放并释放 XmlReader 时取回一些内存,但通常无论如何它都会超出范围。

我以前从来没有打扰过它,但它终于出现在我正在审查的一些代码中。 在代码中运行 SqlCommand 后取消它实际上会以某种方式加速它,还是这只是一些奇怪的程序员迷信?

【问题讨论】:

  • 你分析过代码吗?看看它实际上有多大的影响会很有趣。
  • 有一个重要的边缘情况,调用 Cancel 会产生很大的不同 - 请参阅下面的答案

标签: c# sqlcommand


【解决方案1】:

根据MSDN,这是正确的。

Close 方法填充值 对于输出参数,返回值 和 RecordsAffected,增加 关闭一个所需的时间 用于处理的 SqlDataReader 大型或复杂的查询。当。。。的时候 返回值和数量 受查询影响的记录不 显着,它需要的时间 关闭SqlDataReader可以减少 通过调用 Cancel 方法 之前关联的 SqlCommand 对象 调用 Close 方法。

奇怪!

【讨论】:

  • 嗯。没想到要查看 SqlDataReader 文档。好收获!
  • 查看@底层代码,很明显它在 Close 上做了相当多的工作,但是,我暂时无法想象这在一天结束时有那么重要。
  • 学到了一些东西 ;-) 虽然我同意你必须在 DB IO 上遇到严重的瓶颈才能注意到变化。
  • @Lucas Heneks,感谢您发布报价。我认为重要的是要注意 cmd.Cancel() 告诉 SQL Server 不要发回输出参数、返回值或 RecordsAffected。通常您会设置 nocount 以禁用发回 RecordsAffected 并且如果有输出参数或返回值您可能想要检索它们,所以我想知道该技术在大多数情况下的适用性。
【解决方案2】:

如果您对ExecuteReader 的调用返回大量行,而您没有读取所有行,则调用Cancel 可能会带来MASSIVE 性能改进 .

为了说明,假设一个查询返回一百万行,并且您在读取前 1000 行后关闭了阅读器。如果您在关闭阅读器之前未能调用CancelClose 方法将在内部枚举剩余的 999,000 行时阻塞

试试看!

【讨论】:

  • 这种方法的主要功能是“不要读取所有行”,这一点怎么强调都不为过。
【解决方案3】:

我们在 Cinchcast 的技术团队进行了一些基准测试,我们发现添加 cmd.Cancel() 实际上会减慢速度。

我们有一个 DALC 调用,用于获取主持人的剧集列表。 我们运行了 1000 次,得到了返回 10 集的平均响应时间。

所以返回 10 个节目 平均取消:0.069s 平均不取消:0.026s

在返回 10 集时运行速度要慢得多。

所以,我再次尝试返回 100 集,看看更大的结果集是否会产生影响。

所以每次通话返回 100 场演出 平均取消:0.132s 平均不取消:0.122s

所以这次的时间差要小得多。虽然在我们通常的用例中不使用 Cancel,但它仍然更快。

【讨论】:

    【解决方案4】:

    在您的示例中,您打开阅读器,阅读所有行,然后单击取消命令,但您没有显示阅读器关闭的位置。

    确保在Dispose/Close之前取消。例如,在此示例中您不会获得性能提升(不幸的是,实际代码在生产中):

    using (var rdr = cmd.ExecuteReader (CommandBehavior.Default))
    {
       retval = DocumentDir.DBRead (rdr);
    }
    
    // Optimization.  Allows reader to close more quickly.... NOT!
    cmd.Cancel ();  // bad!
    

    可惜它已经被 Using 语句关闭了!

    这是实现潜在好处的阅读方式:

    using (var rdr = cmd.ExecuteReader (CommandBehavior.Default))
    {
       retval = DocumentDir.DBRead (rdr);
    
       // Optimization.  Allows reader to close more quickly.
       cmd.Cancel ();
    }
    

    来自MSDN SqlCommand.Cancel

    在某些极少数情况下,如果您调用 ExecuteReader,然后在调用 Cancel 之前调用 Close(隐式或显式),然后调用 Cancel,则取消命令将不会发送到 SQL Server,结果集可以继续在调用 Close 后进行流式传输。 为避免这种情况,请确保在关闭读取器或连接之前调用 Cancel。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多