2010-02-25 109 views
26

我正在構建一個應用程序,並且希望將多個查詢分批到數據庫的一次往返。例如,假設單個頁面需要顯示用戶列表,組列表和權限列表。在一次往返中執行多個SQL命令

所以我存儲了特效(或簡單的sql命令,如「select * from Users」),我想執行其中的三個。但是,要填充這一頁,我必須進行3次往返。

現在我可以編寫單個存儲過程(「getUsersTeamsAndPermissions」)或執行單個SQL命令「select * from Users; exec getTeams; select * from Permissions」。

但我想知道是否有更好的方法來指定在一次往返中做3次操作。好處包括更容易進行單元測試,並允許數據庫引擎對查詢進行平行化。

我使用C#3.5和SQL Server 2008

+2

如果這是ASP.Net,並且數據庫服務器緊挨着Web服務器(或者它只是一個內部應用程序),那麼這很可能是一個不成熟的優化.. – Earlz 2010-02-25 18:18:24

+0

@Earlz,或者過早優化或者解決其他一些設計問題。 – 2010-02-25 18:26:52

+6

每當我回過頭來閱讀這個問題,我感到很開心,有多少人閱讀了我爲這個問題編寫的簡單例子,並假設他們比我更瞭解我的應用程序的性能特徵。 – tster 2014-07-03 15:43:33

回答

8

單一的多部分命令和你提到的存儲過程選項是兩個選項。你不能以他們在db上「並行化」的方式來完成它們。然而,這兩種選擇都會導致單程往返,所以你很棒。無法更有效地發送它們。在sql server 2005以後,完全參數化的多部分命令是非常有效的。

編輯:添加關於爲什麼塞入單個呼叫的信息。

雖然你不想在意過多減少通話,但有可以是合法的原因。

  • 我曾經被限制在一臺大型機上,但每次調用時都有1.2秒的開銷!我是認真的。有些時候我在我的數據庫調用中塞進了一些額外的。不漂亮。
  • 你也可能發現自己處於一種情況,你必須在某處配置sql查詢,而且你不能只進行3個調用:它必須是一個。它不應該是這樣,不好的設計,但它是。你做你必須做的!
  • 有時候當然可以非常好地將多個步驟封裝在存儲過程中。儘管通常不用於節省往返次數,但對於更緊密的交易,獲取新記錄的ID,限制權限,提供封裝,等等等等等等。 (But please don't start using stored procedures all the time.
+0

無論如何,單程往返是最重要的考慮因素。 – tster 2010-02-25 18:07:31

34

喜歡的東西this。這個例子可能不是很好,因爲它沒有正確處理對象,但你明白了。這裏有一個清理版本:

using (var connection = new SqlConnection(ConnectionString)) 
using (var command = connection.CreateCommand()) 
{ 
    connection.Open(); 
    command.CommandText = "select id from test1; select id from test2"; 
    using (var reader = command.ExecuteReader()) 
    { 
     do 
     { 
      while (reader.Read()) 
      { 
       Console.WriteLine(reader.GetInt32(0)); 
      } 
      Console.WriteLine("--next command--"); 
     } while (reader.NextResult()); 

    } 
} 
+2

+1代碼示例。這就是我在一個命令中用多個sql語句討論的問題。 – tster 2010-02-25 18:12:55

+0

感謝你一直在尋找處理連接和命令的正確方法:) – KristianB 2011-10-13 09:47:31

0

構建一個臨時表?插入所有結果到臨時表,然後select * from @temp-table

中,

@temptable=.... 
select @temptable.field=mytable.field from mytable 
select @temptable.field2=mytable2.field2 from mytable2 

等..只有一個訪問數據庫,但我不知道它實際上是更有效的。

+0

,這將使4往返;) – tster 2010-02-25 18:08:47

+0

@tster,那是怎麼回事? – Earlz 2010-02-25 18:17:21

2

做一個往返vs三個確實會更有效率。問題是,它是值得的麻煩。整個ADO.Net和C#3.5工具集和框架都與您嘗試執行的操作相反。 TableAdapters,Linq2SQL,EF,所有這些都喜歡處理簡單的one-call == one-resultset語義。因此,您可能會通過嘗試擊敗框架提交來降低一些嚴重的生產力。

我會說,除非你有一些嚴重的測量結果顯示你需要減少往返次數,否則棄權。如果你最終要求這個,那麼使用一個存儲過程來至少給出一種API類型的語義。

但是如果你查詢真的是你發佈的內容(即選擇所有用戶,所有隊和所有權限),那麼你obviosuly有更大的魚減少了往返之前炒...首先減少結果集。

+0

我把這些放在頭頂。 – tster 2010-02-25 18:08:23

+0

+1告訴我不要打擾。相信我,在我開始這樣做之前,我會做很多其他事情,因爲Web服務器和數據庫服務器彼此非常接近。 – tster 2010-02-25 18:11:15

+0

但我認爲MSTF應該實現一些對象(也許應該在ObjectContext中有一個IDisposable屬性,當它進入時,將一次執行所有累積的查詢,設置每個強類型的reslultset。 – Shimmy 2010-11-30 12:06:45

0

首先,3次往返並不是什麼大不了的事情。如果你正在談論往返那麼這將是另一回事,但只有3次往返旅行,我會conderer這definitley是一個過早優化的情況。

這麼說,我會做這樣的方式很可能是執行的使用SQL存儲3個procuedres:

exec dbo.p_myproc_1 @param_1 = @in_param_1, @param_2 = @in_param_2 
exec dbo.p_myproc_2 
exec dbo.p_myproc_3 

然後,您可以通過返回的結果集進行迭代,你會如果你直接執行多個行集。

1

這個this這個鏈接可能有幫助。

考慮使用至少相同的連接開放;根據它所說的here,打開連接幾乎是實體框架中性能成本的最高領導者。

+0

連接池幾乎總能確保你只打開一個物理連接,因此通常您不必擔心打開多個連接的性能成本。 – Rory 2016-05-28 16:37:46