2011-08-23 86 views
2

上下文:SQL Server 2008.內部連接有2個表。 擁有4000萬行的事實表包含患者密鑰和所服用的藥物以及其他事實。藥物密鑰和患者密鑰在該順序中有一個獨特的索引(非聚集)。 維度表是藥物清單(70行)。 加入是基於藥物密鑰(代理鍵)獲得藥物代碼(商業代碼)。 查詢:SQL Server查詢的奇怪執行計劃

SELECT a.PKey, a.SomeFact, b.MCode 
FROM tblFact a 
JOIN tblDIM b ON a.MKey = b.MKey 

所有返回的列是整數。 上述查詢在7分鐘內運行,其執行計劃顯示使用(MKey,PKey)上的索引。該指數在運行前重建。 當我禁用事實表上的索引(或將數據複製到具有相同結構但沒有索引的新表)時,相同的查詢僅需要1:40分鐘。

IO統計數據也令人驚歎。

有索引:表'tblFACT'。掃描計數70,邏輯讀取190296338,物理讀取685138,預讀讀取98713

沒有索引:表'tblFACT_copy'。掃描計數17,邏輯讀取468891,物理讀取0,預讀讀取419768

問題:爲什麼它會嘗試使用索引並降低效率低下的路徑?

+1

我們可以看到索引定義和執行計劃嗎?它是否必須對您的索引執行RID_LOOKUP? –

回答

0

在極少數情況下,數據庫選擇不正確的執行計劃。在這種情況下,索引用於連接,但由於所有數據都是從兩個表中提取的,因此只掃描整個表會更快。 如果將WHERE子句添加到查詢中,索引版本會更快,因爲如果沒有索引,它仍然需要掃描整個表格,而不是隻抓取它需要的一小部分記錄。

可能有一些指令鼓勵數據庫不使用索引或使用不同的索引,但我不太瞭解SQL服務器。

+0

只是FYI,'FROM YourTable WITH(INDEX(0))'強制執行表掃描 – Andomar

+0

@Andomar:謝謝,好的技巧 – vuht2000

+0

而在SQL Server 2008 R2 SP1和Denali中,可以使用FORCESCAN強制掃描任何索引 - 儘管可能會有太多的非學術案例可能會有用。根據你的口音,在擁擠的演示廳裏大聲說出這個詞也可能很幽默。 :-)請參閱http://sqlblog.com/blogs/aaron_bertrand/archive/2011/04/22/sql-server-2008-r2-sp1-ctp-is-now-available.aspx和http:// msdn。 microsoft.com/en-us/library/ms187373%28SQL.110%29.aspx –

0

你的統計信息是最新的?請與:

SELECT object_name = Object_Name(ind.object_id) 
,  IndexName = ind.name 
,  StatisticsDate = STATS_DATE(ind.object_id, ind.index_id) 
FROM SYS.INDEXES ind 
order by 
     STATS_DATE(ind.object_id, ind.index_id) desc 

的更新:

exec sp_updatestats; 
+0

OP表示「索引在運行之前就重建了」:索引統計信息總是通過索引重建進行更新(但不是列索引)。基本上,tblFact索引不包括 – gbn

1

您需要添加SomeFact爲包括關於tblFact指數,使其covering

目前,該表將被訪問兩次:一次是爲索引,然後再進行查找,以得到SomeFact無論是作爲一個RID或鍵查找(取決於是否有一個聚集索引)

這沒有按」 t適用於tblDIM,因爲我認爲MKey是隱式涵蓋的聚集索引

+0

+1 - 我相信他仍然需要將聚簇索引 – JNK

+0

的所有頁面與當前執行計劃完美結合,訪問該索引70次(等於該行中的行數昏暗的桌子)。有關鍵查找(聚集索引)。我不願意讓索引完全覆蓋,因爲事實列因查詢而異。 – vuht2000

+0

@ vuht2000:三個選項:1.沒有索引,每個查詢都會採用1:40 2.使(Mkey,Pkey)聚集索引3.使當前索引覆蓋。您的選擇... – gbn