2010-10-20 26 views
2

我正在閱讀有關數據庫書籍中的索引的內容,我在想,如果我假設在其中使用非常量表達式的WHERE子句不會使用索引,那麼我是否正確。 所以,如果我有SQL中的WHERE子句的索引性能

SELECT * FROM statuses WHERE app_user_id % 10 = 0; 

這不會用在app_user_id創建一個索引。但是

SELECT * FROM statuses WHERE app_user_id = 5; 

將使用app_user_id上的索引。

回答

5

通常(還有其他選項)數據庫索引是B-Tree,這意味着您可以對其執行範圍掃描(包括等式掃描)。

條件app_user_id % 10 = 0無法使用單個範圍掃描進行評估,這就是數據庫可能不會使用索引的原因。

它仍然可以決定以另一種方式使用索引,即全面掃描:讀取整個表比讀取整個索引需要更多的時間。另一方面,在閱讀指數之後,您仍然可以回到表格中,因此總體成本可能會更高。

這是由數據庫查詢優化器決定的。

舉幾個例子:

select app_user_id from t where app_user_id % 10 = 0 

在這裏,你不需要表可言,所有必要的數據是在索引中。數據庫很可能會進行完整的索引掃描。

select count(*) from t where app_user_id % 10 = 0 

相同。全索引掃描。

select count(*) from t 

只有app_user_id is not null可以這樣用指數來完成(因爲NULL數據不在指數,至少在甲骨文,至少在單列索引,數據庫可以不同的方式處理這個)。

某些數據庫不需要爲此執行訪問表或索引,它們在元數據中維護行計數。

select * from t where app_user_id = 5 

這是索引的經典場景。數據庫可以查看索引樹的小部分,檢索rowid中的一小部分(如果這是一個唯一索引或主索引),並從表中選擇性地提取這些部分。

select * from t where app_user_id between 5 and 10 

另一個經典索引案例。樹中的範圍掃描返回少量rowid以從表中獲取。

select * from t where app_user_id between 5 and 10 order by app_user_id 

由於索引掃描返回有序的數據,你甚至排序是免費的。

select * from t where app_user_id between 5 and 1000000000 

也許在這裏你不應該使用索引。它似乎匹配了太多的記錄。這種情況下,綁定變量隱藏數據庫的範圍實際上可能是有害的。

select * from t where app_user_id between 5 and 1000000000 
    order by app_user_id 

但是,在這裏,由於排序將是非常昂貴的(即使佔用臨時交換磁盤空間),也許迭代索引順序是好的。也許。

select * from t where app_user_id % 10 = 0 

這很難決定。我們需要所有列,因此最終查詢需要觸摸表格。問題是,是否首先要通過索引。查詢返回大約10%的整個表。這對索引訪問路徑來說可能太高效了。如果優化器有理由相信查詢返回的表少於10%,則索引掃描後訪問表可能會很好。如果表格非常分散(大量刪除的行佔用空間),則相同。

+0

所以基本上你的回答說它取決於數據庫。 – 2010-10-20 04:54:46

+0

和數據。和配置選項。另外,索引是否被使用並不重要。這只是重要的,是否會比其他選擇更快。無論如何,你的推理應該是「我需要運行什麼查詢」,然後相應地設計模式和索引。如果您的%10查詢執行得不夠好,則可能需要對列進行非規範化處理,或者構建功能索引。 – Thilo 2010-10-20 04:58:26