2012-02-13 40 views
13

所以在C#中使用存儲過程我有如下所示(略連接代碼)代碼:執行存儲過程時,使用CommandType.StoredProcedure與使用CommandType.Text有什麼好處?

string sql = "GetClientDefaults"; 

SqlCommand cmd = new SqlCommand(sql); 
cmd.CommandType = CommandType.StoredProcedure; //<-- DO I NEED THIS?? 
cmd.Parameters.AddWithValue("@computerName", computerName); 

如果SQL是一個存儲過程的名稱。現在,這段代碼似乎可以在沒有註釋的行的情況下正常工作。

那麼,我需要這條線嗎?是否有一些表現(或其他)有利於設置?不設置它或將其設置爲文本有沒有好處?

回答

14

根據this blog post中的測試,當您使用CommandType.Text時,SQL Server將通過將語句包裝在sp_executesql中來爲您執行參數化。但是當你使用CommandType.StoredProcedure時,你將參數化它,從而保存數據庫的一些工作。後一種方法更快。

編輯:

設置

我已經做了一些測試,我和這裏的結果。

創建此過程:

create procedure dbo.Test 
(
    @Text1 varchar(10) = 'Default1' 
    ,@Text2 varchar(10) = 'Default2' 
) 
as 
begin 
    select @Text1 as Text1, @Text2 as Text2 
end 

添加跟蹤到它使用SQL Server Profiler。

然後調用它使用下面的代碼:

using System; 
using System.Data; 
using System.Data.SqlClient; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main() 
     { 
      CallProcedure(CommandType.Text); 
      CallProcedure(CommandType.StoredProcedure); 
     } 

     private static void CallProcedure(CommandType commandType) 
     { 
      using (SqlConnection connection = new SqlConnection("Data Source=localhost;Initial Catalog=Test;Integrated Security=SSPI;")) 
      { 
       connection.Open(); 
       using (SqlCommand textCommand = new SqlCommand("dbo.Test", connection)) 
       { 
        textCommand.CommandType = commandType; 
        textCommand.Parameters.AddWithValue("@Text1", "Text1"); 
        textCommand.Parameters.AddWithValue("@Text2", "Text2"); 
        using (IDataReader reader = textCommand.ExecuteReader()) 
        { 
         while (reader.Read()) 
         { 
          Console.WriteLine(reader["Text1"] + " " + reader["Text2"]); 
         } 
        } 
       } 
      } 
     } 
    } 
} 

結果

在這兩種情況下,調用使用RPC製成。

下面介紹一下跟蹤顯示使用CommandType.Text

exec sp_executesql N'dbo.Test',N'@Text1 nvarchar(5),@Text2 nvarchar(5)',@Text1=N'Text1',@Text2=N'Text2' 

這裏是使用CommandType.StoredProcedure結果:

exec dbo.Test @Text1=N'Text1',@Text2=N'Text2' 

正如你所看到的文字呼叫被包裹在一個呼叫sp_executesql如此它是正確參數化的。這當然會造成輕微的開銷,因此我以前的說法使用CommandType.StoredProcedure更快。

另一個值得注意的事情,並且這裏也是那種一個大忌,就是當我創建的過程,而不默認值,我得到了以下錯誤:

Msg 201, Level 16, State 4, Procedure Test, Line 0 Procedure or function 'Test' expects parameter '@Text1', which was not supplied.

這樣做的原因是如何調用至sp_executesql已創建,因爲您可以看到參數已聲明和初始化,但它們未使用。對於呼叫工作,它應該是這個樣子的:

exec sp_executesql N'dbo.Test @Text1, @Text2',N'@Text1 nvarchar(5),@Text2 nvarchar(5)',@Text1=N'Text1',@Text2=N'Text2' 

意思是,當你使用CommandType.Text您必須將參數添加到CommandText除非你總是希望使用默認值。

因此,要回答你的問題

  1. 使用CommandType.StoredProcedure更快。
  2. 如果您使用的是CommandType.Text,那麼您必須將參數名稱添加到對過程的調用中,除非要使用默認值。
+0

-So使用StoredProcedure可能會更快嗎? – MAW74656 2012-02-13 20:48:04

+1

@ MAW74656是的。另請注意,Panagiotis Kanavos回答說,除了SQL Server之外,可能還有其他提供者不知道您正在嘗試執行proc,除非您指定它。 – 2012-02-13 21:34:48

+0

- 我明白關於其他提供者的觀點,只是這個應用程序不太可能需要這種改變。還有很多商業企業應用程序要求您使用SQL Server(任何特定的數據庫服務器),我敢打賭他們不在那裏使用提供程序工廠。 – MAW74656 2012-02-13 21:44:13

5

您將設置此項以允許ADO.NET爲您提供幫助。當您使用CommandType.StoredProcedure時,您只需將CommandText等於存儲過程名稱即可。

舉例來說,這樣的:

YourSqlCommand.CommandType = CommandType.StoredProcedure; 
YourSqlCommand.CommandText = "dbo.YourStoredProc"; 

等同於:

YourSqlCommand.CommandText = "exec dbo.YourStoredProc"; 
+0

- 我不是說「執行」或「dbo」。在任一版本中,它工作得很好。有沒有其他的方法可以幫到你? – MAW74656 2012-02-13 19:58:06

+0

我真的會重新編譯它..調試它,並真正測試..因爲我沒有看到類似的工作,而不必設置CommandTpe ... hummmmm? – MethodMan 2012-02-13 20:01:23

+4

@ MAW74656這是因爲在SQL Server中,如果存儲過程是批處理的第一條語句,則不必鍵入'exec'。 – 2012-02-13 20:01:39

3

的CommandType不是具體到SQL Server。它是IDbCommand接口的一個屬性,它指示底層提供者以特定方式處理CommandText。儘管SQL Server可能會將單字名稱視爲過程,但您不應期望這可以在其他提供程序中使用。

通常,您應該更喜歡使用提供程序生成的類,如DbCommand而不是像SqlCommand這樣的特定類。這樣你就可以簡單地通過改變配置文件中的提供者字符串來定位不同的數據庫。

+0

@PagagiotisKanavos-我想你在這裏打了一場不同的戰鬥。大多數聯機示例代碼使用SQLCommand。但即使我接受這個前提,你仍然沒有說過設置CommandType的效果。 – MAW74656 2012-02-13 20:43:39

+0

沒有戰鬥的戰鬥。你使用一個特定的類,你被綁定到提供者並且必須重寫所有的東西。示例代碼不是生產代碼。至於什麼CommandType呢 - 你認爲你可以通過傳遞名稱並假設默認的CommandType.Text在Oracle中執行存儲過程嗎?無論如何,我絕不會相信生產守則中的意外和無證行爲,只是爲了避免設定價值。 – 2012-02-13 20:51:42

+0

但是它是如何設置的? – MAW74656 2012-02-13 21:10:52

5

實際上有一個巨大的差異。如果指定命令類型StoredProcedure,則添加到SqlCommand的任何參數都將成爲參數過程調用。如果將其保留爲Text,則參數將被添加到批次,而不是過程。爲了說明這一點,讓我們創建一個虛擬的過程:

create procedure usp_test 
    @p1 char(10) = 'foo', 
    @p2 int = 42 
as 
    select @p1, @p2;  
go 

然後編譯這個小C#應用程序:

static void Main(string[] args) 
    { 
     ExecWithType(CommandType.Text); 
     ExecWithType(CommandType.StoredProcedure); 
    } 

    static void ExecWithType(CommandType type) 
    { 
     using (SqlConnection conn = new SqlConnection(Settings.Default.connString)) 
     { 
      conn.Open(); 
      using (SqlCommand cmd1 = new SqlCommand("usp_test", conn)) 
      { 
       cmd1.CommandType = type; 
       cmd1.Parameters.AddWithValue("@p1", "bar"); 
       cmd1.Parameters.AddWithValue("@p2", 24); 
       using (SqlDataReader rdr = cmd1.ExecuteReader()) 
       { 
        while (rdr.Read()) 
        { 
         Console.WriteLine("Type: {0} Result: @p1: {1} @p2: {2}", type, rdr[0], rdr[1]); 
        } 
       } 
      } 
     } 
    } 

結果是:

Type: Text Result: @p1: foo  @p2: 42 
Type: StoredProcedure Result: @p1: bar  @p2: 24 

哎喲!對於CommandType.Text設置,儘管參數已傳遞到批次,但它們未傳遞到過程。很多小時的調試樂趣源...

+0

-So帶參數,無灰色區域,CommandType.StoredProcedure絕對更好,更準確,更快。 – MAW74656 2012-02-14 15:37:35

相關問題