2013-03-06 100 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