2008-08-28 60 views
21

工作,如果我有這樣的查詢:做索引與「IN」的條款

Select EmployeeId 
From Employee 
Where EmployeeTypeId IN (1,2,3) 

,我在EmployeeTypeId場有一個指標,不SQL服務器仍然使用該索引?

+2

我不明白爲什麼這不是一個真正的問題。 – nawfal 2012-07-16 19:19:43

回答

13

是的,沒錯。如果您的員工表有10,000條記錄,並且只有5條記錄在(1,2,3)中有employeetypeID,那麼它很可能會使用索引來獲取記錄。但是,如果它發現9,000條記錄在(1,2,3)中具有employeeIDType,那麼它很可能只是進行表掃描以獲得相應的EmployeeID,因爲它只是運行整個表的速度比轉到索引樹的每個分支並單獨查看記錄。

SQL Server做了很多工作來試圖優化查詢的運行方式。但是,有時候它沒有得到正確的答案。如果您知道SQL Server未使用索引,那麼通過查看查詢分析器中的執行計劃,可以告訴查詢引擎使用特定索引,並對查詢進行以下更改。

Select EmployeeId From Employee WITH (Index(Index_EmployeeTypeId)) Where EmployeeTypeId IN (1,2,3) 

假設您在EmployeeTypeId字段中的索引名爲Index_EmployeeTypeId。

4

通常它會,除非IN子句覆蓋太多的表,然後它會做表掃描。在你的特定情況下找出最好的方法是在查詢分析器中運行它,並檢查執行計劃。

2

因此,「IN」子句可能會運行表掃描,但優化程序將嘗試並找出處理它的最佳方法?

是否使用索引不會因查詢類型而異,因爲表中數據的類型和分佈多少,表格數據的最新情況以及列的實際數據類型。

其他海報是正確的,指數將在一個表中使用掃描,如果:

  • 查詢將不超過行的一定比例索引訪問更多(比如說〜10%,但應因人而異在DBMS之間)。
  • 或者,如果列中有很多行,但相對較少的唯一值,那麼執行表掃描也可能會更快。

其他可能不那麼明顯的變量是確保被比較值的數據類型相同。在PostgreSQL中,我認爲如果你在float上過濾,但是你的列是由int組成的,那麼索引就不會被使用。還有一些運營商不支持索引使用(同樣,在PostgreSQL中,ILIKE運算符就是這樣)。

如前所述,如果有疑問,請務必檢查查詢分析器,並且您的DBMS文檔是您的朋友。

3

除非技術以我無法想象的方式得到改進,否則顯示的「IN」查詢將產生一個結果,它有效地對三個結果集進行OR運算,其中一個用於「IN」名單。 IN子句成爲每個列表的相等條件,並在適當的情況下使用索引。在唯一ID和足夠大的表格的情況下,我希望優化器使用索引。

如果在列表中的項目要成爲非唯一然而,我想在一個「TYPEID」是一個外鍵的例子,那麼我更感興趣的分佈。我想知道優化器是否會檢查列表中每個值的統計信息?假設它檢查第一個值,並發現它在20%的行中(足夠大的表格很重要)。它可能會進行表掃描。但是同樣的查詢計劃是否會用於其他兩個,即使它們是唯一的?

它可能實際意義 - 有點像一個Employee表可能是足夠小,它會在內存中緩存保持和你可能不會注意到,和索引檢索之間的差異呢。

最後,當我說教時,要小心IN子句中的查詢:它通常是一種快速的方式來獲得某些工作,並且(至少對我而言)可以是表達需求的一種好方法,但它幾乎總是最好重新加入。你的優化器可能足夠聰明來發現這一點,但它可能不會。如果您目前沒有性能檢查對生產數據卷,這樣做 - 在基於成本的優化,這些日子裏,你不能確定查詢計劃,直到你有一個滿負荷和有代表性的統計數據。如果不能,那麼可以在生產準備的驚喜...

1

@Mike:謝謝你的詳細分析。你肯定會有一些有趣的觀點。我發佈的例子有點微不足道,但問題的基礎來自使用NHibernate。

與NHibernate,你可以寫這樣的條款:

int[] employeeIds = new int[]{1, 5, 23463, 32523}; 
NHibernateSession.CreateCriteria(typeof(Employee)) 
.Add(Restrictions.InG("EmployeeId",employeeIds)) 

的NHibernate然後生成一個查詢,看起來像

select * from employee where employeeid in (1, 5, 23463, 32523) 

所以當你和其他人指出,它看起來像有將會是索引被使用或表掃描發生的時間,但是直到運行時才能真正確定。

0
Select EmployeeId From Employee USE(INDEX(EmployeeTypeId)) 

這個查詢將搜索使用您所創建的索引。這個對我有用。請做一個嘗試..