2012-08-29 62 views
1

我在Oracle 11GR2中有一個簡單的搜索存儲過程,其中有超過160萬條記錄。我很困惑的事實是,如果我想在一個列內搜索一個工作,比如「%boston%」,那將需要12秒。我有一個關於名稱欄目的索引。Oracle字符串搜索性能問題

select description from travel_websites where name like "%boston%"; 

如果我只搜索一個以波士頓開頭的詞,如「boston%」,則只需要0.15秒。

select description from travel_websites where name like "boston%";

我增加了一個索引提示,並試圖迫使優化器使用我的索引上的姓名欄,它並沒有幫助。

select description /*+ index name_idx */ from travel_websites where name like "%boston%"; 

任何建議將不勝感激。

+1

除了下面的答案,如果在文本列中存在關於搜索詞的位置的一致規則,則可以考慮基於函數的索引。例如。如果波士頓(或任何其他搜索術語)從位置X開始或在(第一,第二等)空間之後開始。然後將where謂詞與索引函數進行匹配可以導致使用該函數。 – Karl

回答

5

對於具有前導通配符的謂詞(即like '%boston%'),不能使用索引範圍掃描。如果您考慮索引如何存儲在磁盤上 - 如果您不知道要搜索的字符串的第一個字符是什麼,則無法遍歷索引以查找與該字符串匹配的索引條目。您可以對每個葉塊的索引進行全面掃描,並在那裏搜索name以查看它是否包含所需的字符串。但是這需要對索引進行全面掃描,然後您必須訪問索引中獲得的每個ROWID的表以便獲取任何不屬於剛剛完全掃描的索引的列。根據表和索引的相對大小以及謂詞的選擇性,優化器可以輕鬆地決定,如果您要搜索前導通配符,只需執行表掃描就可以更快。

Oracle does support full text search,但你必須使用Oracle Text的,即要求你建立在name列的Oracle Text的索引和使用CONTAINS operator做搜索,而不是使用LIKE查詢。 Oracle Text是非常強大的產品,因此在構建索引,刷新索引和構建查詢時,可以考慮相當多的選項,具體取決於您希望獲得多少複雜性。

您的索引提示未正確指定。假設name上有一個索引,該索引的名稱是name_idx,並且您想要強制對索引進行全面掃描(僅僅重申,如果存在領先的索引,則索引上的範圍掃描不是有效選項通配符),你會需要像

select /*+ index(travel_websites name_idx) */ description 
    from travel_websites 
where name like '%boston%' 

沒有保證,但是,全索引掃描將是比任何一個全表掃描更高效。並且完全可能的是,優化程序已經選擇完全掃描索引而沒有提示(您沒有指定查詢計劃針對三個查詢)。

+1

非常好的評論。愛它。 – dave

2

Oracle(以及我所知道的大多數其他數據庫)默認情況下會對索引字符串進行索引,以便索引只能用於從字符串的起始開始查找字符串匹配。這意味着,LIKE 'boston%'(startswith)將能夠使用該索引,而LIKE '%boston'(endswith)或LIKE '%boston%'(contains)不會。

如果您確實需要可快速查找子字符串的索引,則不能使用字符串的常規索引類型,但可以使用TEXT索引,這些索引可能會需要稍微不同的查詢語法。