2011-03-01 65 views
2

目前,我發現在我們的應用程序一個查詢及其執行計劃「索引掃描」。好了,這裏有一些背景:SQL Server 2005中執行計劃的問題

  1. 它有三個列,類型爲「idType :bigint「
  2. 手頭上只有200件爆炸物品
  3. 有列(a:PK,b:FK,c:FK),我們有兩個索引(一個聚簇索引(b,c),一個PK非聚集索引(a))

以下是我們的查詢:

exec sp_executesql N'select b,a from table where b in (@P0, @P1, @P2, 
    @P3, @P4, @P5, @P6, @P7, @P8, @P9)', 
    N'@P0 bigint, @P1 bigint, @P2 bigint, @P3 bigint, @P4 bigint, @P5 bigint, 
     @P6 bigint, @P7 bigint, @P8 bigint, @P9 bigint', 
    94, 161, 4, 50, 166, 52, 53, 90, 100, 123 

它從執行計劃顯示爲pk索引上的「索引掃描」...出了什麼問題?

如果我使用相同的查詢,但不能使用「sp_executesql的」,如:

select b,a from table where b in(94,161,4,50,166,52,53,90,100,123) 

它顯示「聚集索引查找」如我所料

爲什麼會使用SQL Server「索引掃描」的第一個查詢?它是否與函數 「sp_executesql」本身有關?

謝謝你在進階 萬斯

+1

實際「CREATE TABLE」和「CREATE INDEX」語句比描述更容易理解(一般說明:只要刪除多餘的列,如果表格很寬,並且問題可以用列的子集來演示) – 2011-03-01 09:16:27

+0

嘗試在存儲過程中執行代碼,查看執行計劃是否與sp_execute或T-SQL計劃相同將會很有趣。 (這不一定是解決您的問題,我只是想獲得更多信息) – Tony 2011-03-01 09:53:37

+0

謝謝大家的回覆! @Tony我把第一個查詢'exec sp_executesql N'...)在一個SP中,並得到「index_scan」相同。這個問題涉及到我的測試表的值是小的嗎?我只有200個項目,所以sql服務器不會「優化」它的查詢執行嗎? – Vance 2011-03-01 10:03:08

回答

1

我不得不看看類似的查詢在我自己的數據庫的執行計劃,可以看到有差別,但我不能完全解釋它;我只是認爲我的發現可能有用。

的差異似乎是由於在編譯的查詢參數的使用。

在下面的例子中我使用的是從一個數據庫中,我有一個名爲[資源]表中,你將不得不更改名稱爲您查詢。

正如你已經發現直接在管理工作室結果執行查詢在索引查找

T_SQL Query

使用版本參數給出了一個掃描

enter image description here

如果完全準備好聲明,然後將其傳遞給數據庫,例如

exec('select id from [Resource] where id in (1,5,7,9,10)') 

你會得到一個索引查找再次

enter image description here

有趣的是看緩存計劃

SELECT cp.objtype,cp.usecounts,q.TEXT 
FROM sys.dm_exec_cached_plans cp 
cross apply sys.dm_exec_query_plan(cp.plan_handle) p 
cross apply sys.dm_exec_sql_text(cp.plan_handle) AS q 
WHERE cp.cacheobjtype = 'Compiled Plan' 

這三個語句執行我得到

 
objtype usecounts text 
------- --------- ---- 
Adhoc  1   select id from [Resource] where id in (1,5,7,9,10) 
Prepared 1   (@p1 int, @p2 int, @p3 int, @p4 int, @p5 int)select id from [Resource] where id in (@p1, @p2, @p3, @p4, @p5) 
Adhoc  1   select id from [Resource] where id in (1,5,7,9,10) 

正如你所看到的,SQL是完全不同的。不幸的是,就我所能解釋的索引選擇差異而言,你所看到的是。也許別人可以更進一步呢?

編輯1:我已經閱讀了一些內容,它涉及到優化器必須創建一個計劃來滿足所有可能的參數值(正如Kragen在他的回答中所述)。

我發現這篇文章中相同的信息:Dynamic Search Conditions in T-SQL

編輯2:針對馬丁的評論,這裏是他的SQL語句的執行計劃

enter image description here

+0

我想它歸結爲選擇性。如果你從這裏得到5個id,選擇top(5)id,從[Resource]組中按COUNT(*)desc'選擇COUNT(*),然後嘗試將它們作爲文字來掃描還是查找? – 2011-03-01 12:33:36

+0

@Martin:我發佈了這個查詢,但我想我誤解了你試圖達到的目標。 – Tony 2011-03-01 12:47:48

+0

是的,你有!假設你的查詢顯示5個最常見的id是'100,101,102,103,104'我想知道你會從[Resource]中得到什麼樣的計劃,其中id爲(100,101,102,103,104)'如果這仍然給你一個尋找計劃然後我可以對於參數化版本進行掃描根本沒有理由,因爲這應該是最糟糕的情況。 – 2011-03-01 13:03:55

1

的差異可能這是由於在不同的數據或不同的參數意味着表掃描/索引搜索合適時執行的緩存查詢計劃。 (SQL命令文本本身不同,因此它們在計劃緩存中都有不同的條目)。如果你想測試這一點,你可以使用此命令清除計劃緩存:

DBCC FREEPROCCACHE -- Don't run me on a production SQL server! 

然後嘗試再次運行這兩個命令,看看是否有還是有區別的(也有說是生產安全的,如果上面的命令版本你願意通過計劃緩存挖掘)

請注意,表掃描並不總是一件壞事 - 特別是當表狹窄,並沒有多少行(這看起來是在你的情況下例)。在這種情況下,表掃描可能比索引查找有效得多。