2013-03-06 178 views
2

如SQL Profiler中所见,如何调用SqlCommand.ExecuteReader比SQL批处理本身完成所需的时间更少?SqlCommand.ExecuteReader持续时间小于SQL Profiler批处理持续时间

我在其中呼吁SqlCommand.ExecuteReader,一个控制台应用程序运行以下简单的代码,我的时间用秒表对象:

var swQueryTime = new Stopwatch(); 

     var conn = new SqlConnection("Data Source=.;Initial Catalog=master;Trusted_Connection=True;"); 
     conn.Open(); 
     string sql = string.Format(@"select * from sys.dm_os_memory_clerks; select * from sys.dm_os_performance_counters "); 

     for (int i = 0; i < 10; i++) 
     {     
      var comm = new SqlCommand(sql, conn); 
      swQueryTime.Restart(); 

      var dr = comm.ExecuteReader(); 

      swQueryTime.Stop(); 

      Console.WriteLine("ElapsedMilliseconds: {0}", swQueryTime.ElapsedMilliseconds); 

      dr.Close(); 
      comm = null; 
     } 

平均SQL批处理持续时间比什么报道更长的4倍在.Net方面。

我检查过的profiler是特别报告毫秒。

我没有使用SqlCommand.ExecuteReader的异步版本。

事件探查器持续时间不是所有时间跨多个线程/核心的总和,这些是我使用探查器开始和结束时间读取和验证的结果。

意见赞赏。

+0

+1:用于检查Sql Profiler Milli/Micro-second的事情。 – RBarryYoung 2013-03-06 13:24:15

+0

您是否在Profiler中检查了Sql语句本身的持续时间?它总是比批处理持续时间少一点,通常差别很小,但有时候很重要。 – RBarryYoung 2013-03-06 13:26:16

+0

是的,我已经检查了报表的持续时间 - 这两个报表总和为预计的批处理持续时间。 – user2139987 2013-03-06 13:43:00

回答

2

因为您只有批次的开始时间。如果您消耗的数据也一样,时间可能会排队:

using(var dr = comm.ExecuteReader()) { 
    do { 
     while(dr.Read()) {} 
    } while (dr.NextResult()); 
} 

顺便说一下,也有可以改变某些查询的性能几个SET选项 - 不知道应该在这里适用,但它可以显着影响已计算+持久值的表:如果SET值与创建列时的设置不兼容,则需要重新运行每行的计算。这是,特别是如果您正在对该列进行过滤,则必须对已计算的+持久索引列进行过滤 - 它必须执行表扫描(或类似操作),而不是索引扫描/索引查找。

+0

+1:这可能是。 – RBarryYoung 2013-03-06 13:29:13

+0

是的,这使得探查器和ExecuteReader在时间上达成一致 - 谢谢!我对ExecuteReader的阅读让我相信它在等待所有数据被返回之后才转到下一个语句 - 你知道这种替代行为是否在任何地方被记录? – user2139987 2013-03-06 13:53:54

+0

@ user2139987我还没有检查过,但基本上它返回的是流的TDS - 您可以在流到达流的末尾之前就开始读取数据。当然,使用SequentialAccess模式时显然是这样,因为它甚至可以将单个列作为流读取。如果您在数据结束之前尝试访问'out' /'ref'参数 - 它们会返回* last *,您还可以看到此流式行为的副作用。你也可以做一些事情,比如在长时间选择后提出一个sql错误 - 如果你在结束之前关闭阅读器,你可能永远不会看到错误。 – 2013-03-06 13:57:57