2009-09-08 25 views
3

情況:c#,sql 2000爲什麼參數在where子句中比字面值慢?

我有一張桌子,我們稱之爲'mytable',有三千萬行。 主鍵是由域A和B的了:

A char(16) 
B smallint(2) 

當我做這樣的搜索,它運行非常緩慢(如它做了全表)

string a="a"; 
int b=1; 
string sql = "select * from table(nolock) where [email protected] and [email protected]"; 
using (SqlCommand cmd = new SqlCommand(sql, conn)) 
{ 
    cmd.Parameters.AddWithValue("@a", a); 
    cmd.Parameters.AddWithValue("@b", b); 
    using (SqlDataReader rdr = cmd.ExecuteReader()) {...} 
} 

將其更改爲然而,它運行得非常快(例如它觸及索引):

string where = 
    String.Format("a='{0}' and b={1}", a, b); 

string sql = "select * from table(nolock) where " + where; 
using (SqlCommand cmd = new SqlCommand(sql, conn)) 
{ 
    using (SqlDataReader rdr = cmd.ExecuteReader()) {...} 
} 

究竟是怎麼回事?對我來說似乎很陌生。

+0

嘗試重新啓動數據庫服務器並顛倒測試順序。所有這些的目標是排除SQL Server部分的緩存。 – 2009-09-08 06:38:16

+0

不幸的是不是生產服務器的選項。 – Chris 2009-09-08 06:39:09

+0

這可能會有所幫助 - 但可能不會:http://stackoverflow.com/questions/1211287/getting-a-query-to-index-seek-rather-than-scan – PaulB 2009-09-08 06:41:02

回答

8

參數和列匹配的數據類型?它們看起來並不如此datatype precedence適用

該列是smallint,但您發送int。該列將被轉換爲int,因爲它具有更高的優先級。所以它不會使用索引。

+0

使用不匹配的類型是我目睹並墮入自己的常見錯誤。是的,如果它是隱式轉換的字段(而不是參數),那麼你可以很好地並且真實地得到#### ed。理解類型優先級以及索引如何工作(以及不工作)將有助於理解這裏。 – MatBailie 2009-09-08 12:38:08

3

如果您聲明b變量爲short而不是int,它會產生什麼影響嗎? 如果您明確指定參數的類型,它是否會有所作爲? 如果您使用「where a = @ a和b = @ b」而不是逗號形式,它有什麼區別嗎?

我同意這聽起來很奇怪,我真的不希望這些變化有任何幫助,但它可能值得一試。

+0

對不起,逗號只是我抄寫我的代碼很糟糕。將解決。 至於短,值得一試。 – Chris 2009-09-08 06:38:06

+0

確實,設置參數類型值得一試。 – 2009-09-08 06:44:12

+0

這實際上會產生巨大的差異... – gbn 2009-09-08 06:47:56

0

您可以告訴SQL Server查詢使用哪個索引。使用WITH (INDEX = INDEX_ID)選項,其中INDEX_ID是索引的ID。

獲取索引ID與:

​​

所以儘量然後:

SELECT * FROM table(NOLOCK) WITH (INDEX = 1) WHERE [email protected] and [email protected] 
+0

sql服務器真的很厚我需要提示索引? – Chris 2009-09-08 06:47:25

+0

@Chris:不:這是因爲你有數據類型不匹配。索引提示將無濟於事。 – gbn 2009-09-08 06:49:02

+0

我從來沒有,但選擇存在 – Scoregraphic 2009-09-08 06:51:03

0

正如@gbn說,設置數據類型應該很容易讓你的。

string where = 
    String.Format("a='{0}' and b={1}", a, b); 

在上面的示例中,您告訴SQL將參數a視爲char。
而在其他示例中,它將被視爲varchar。

使用SQL事件探查器查看在這兩種情況下執行的SQL是什麼。這應該爲你清除它。

0

在第一種情況下,您將向該命令添加SqlParameter類。執行該命令時,很可能會生成錯誤數據類型的DECLARE語句。 (您可以使用SQL跟蹤驗證此情況。)如果是這種情況,優化程序將無法選擇正確的索引並回退到表掃描。

如果您使用存儲的proc代替,則會強制參數進入您聲明的數據類型。但是,如果您在參數上指定SqlDbType,仍然可以從代碼執行此操作。

相關問題