oracle like 上強制使用索引

2022-08-30 06:33:10 字數 3105 閱讀 6876

當where子句對某一列使用函式時,除非利用這個簡單的技術強制索引,否則oracle優化器不能在查詢中使用索引。

通常情況下,如果在where子句中不使用諸如upper、replace 或substrd等函式,就不能對指定列建立特定的條件。但如果使用了這些函式,則會出現乙個問題:這些函式會阻礙oracle優化器對列使用索引,因而與採用索引的情況相比較,查詢會花費更多的時間。

慶幸的是,如果在使用函式的這些列中包含了字元型資料,可以用這樣一種方法修改查詢語句,以達到強制性使用索引,更有效地執行查詢。這篇文章介紹了涉及的技術,並說明了在兩種典型情況下怎樣實現。

大小寫混合情況

在討論由於函式修改了列的內容,如何強制使用索引前,讓我們首先看看為什麼oracle優化器在這種情況下不能使用索引。假定我們要搜尋包含了大小寫混合的資料,如在addressbook表的name列。因為資料是使用者輸入的,我們無法使用已經統一改為大寫的資料。為了找到每乙個名為john的位址,我們使用包含了upper子句的查詢語句。如下所示:

select * from addressbook t where upper(t.name) like 'john';

使用這種查詢語句(已設定autotrace),可得到下列結果:(以下是在pl/sql developer中檢視執行計畫的效果:)

可以看到,在這種情況下,oracle優化器對addressbook表作了一次完整的掃瞄,而沒有使用name列的索引。這是因為索引是根據列中資料的實際值建立的,而upper函式已經將字元轉換成大寫,即修改了這些值,因此該查詢不能使用這列的索引。優化器不能與索引項比較」john」,沒有索引項對應於」john」-只有」john」 。

值得慶幸的是,如果在這種情況下想要強制使用索引,有一種簡便的方法:只要在where子句中增加乙個或多個特定的條件,用於測試索引值,並減少需要掃瞄的行,但這並沒有修改原來sql 編碼中的條件。以下列查詢語句為例:

select address from addressbook 

where upper(name) like 'john' and (name like 'j%' or name like 'j%');

使用這種查詢語句,可得到下列結果:

現在,優化器為where 子句中and 聯結的兩個語句中每乙個語句確定的範圍進行掃瞄—-第二個語句沒有引用函式,因而使用了索引。在兩個範圍掃瞄後,將執行結果合併。(我個人感覺是:對於whwere子句中通過and連線的各條件,如果某些條件可以使用索引,則oracle會優先使用這些條件,這樣就可以快速定位符合條件的記錄,然後在過濾之後的記錄中再應用其他不能使用索引的條件。)

在這個例子中,如果資料庫有成百上千行,可以用下列方法擴充where 子句,進一步縮小掃瞄範圍:

select address 

from addressbook 

where upper(name) like 'john' and (name like 'jo%' or name like 'jo%' or name like 'jo' or name like 'jo' );

得到的結果與以前相同,但是,其執行過程如下所示,表明有4個掃瞄範圍。

如果試圖進一步提高查詢速度,我們可以在特定的」name like」條件中指明3個或更多的字元。然而,這樣做會使得where子句十分笨重。因為需要大小寫字元所有可能的組合-joh ,joh,joh,joh等等。除此之外,指定乙個或兩個字元已足以加快查詢的執行速度了。

現在讓我們看看,當我們引用不同的函式時,怎樣運用這個基本技術。

使用replace的情況

正如名字不總是以大寫輸入一樣,**號碼也會以許多格式出現: 如 123-456-7890, 123 456 7890,(123)456-7890 等等。

如果在列名為 phone_number中搜尋上述號碼時,可能需要使用函式replace以保證統一的格式。如果在phone_number列中只包含空格、連字元和數字,where 子句可以如下所示:

where replace(replace(phone_number , '-' ) , ' ' ) = '1234567890'

where子句兩次使用replace 函式去掉了連字元和空格,保證了**號碼是簡單的數字串。然而,該函式阻止了優化器在該列使用索引。因此,我們按如下方法修改where子句,以強制執行索引。

where replace(replace(phone_number, '-' ) , ' ' ) = '1234567890' and phone_number like '123% '

如果我們知道資料中可能包含圓括號,where 子句會稍微複雜一點。我們可以再增加replace 函式(去掉圓括號、連字元和空格),按如下所示擴充增加的條件:

where replace(replace(replace(replace(phone_number , ' - ' ) ,' '), '( ' ) , ' ) ' ) = '1234567890' and (phone number like ' 123% ' or phone_number like ' (123% ' ) '

該例強調了巧妙地選用where 子句條件的重要性,而且,這些條件不會改變查詢結果。你的選擇應基於完全了解該列中存在的資訊型別。在該例中,我們需要知道 phone_number 資料中存在幾種不同的格式,這樣,我們能夠修改where 子句而不會影響查詢結果。

正確的條件

以後當你遇到包含character 資料修改函式列的where 子句時,應考慮怎樣利用增加乙個或兩個特定的條件,迫使優化器使用索引。適當地選擇一組特定的條件能減少掃瞄行,並且強制使用索引不會影響查詢結果—-但卻提高了查詢的執行速度。

動手測試了一下並對原文例子進行了一點點修改。另外對於本文所述情況我更傾向於使用函式索引。

測試指令碼:

create table addressbook(

name varchar2(20),

address varchar2(100)

);create index idx_addressbook_name on addressbook(name);

insert into addressbook values('john','北京');

insert into addressbook values('andy','天津');

insert into addressbook values('frank','河北');

from:網易部落格

如何在CloudFoundry上強制使用https

cloud foundry平台一般都提供http https兩種協議,但是某些時候我們只想使用https,這時候我們就可以通過cf提供的x forwarded proto來處理 以flask為例,在應用中加上如下語句即可 return redirect request.url.replace htt...

強制使用GPU

對於tensorflow,宣告session的時候加入device count 即可 import tensorflow as tf sess tf.session config tf.configproto device count 對於keras,則呼叫後端函式,設定其使用如上定義的sessio...

oracle強制索引使用

強制索引格式 select tablename.from tablename table alias where fieldname 說明 index table alias indexname 必須出現在select 之後,字段之前 tablename 為表名,如果sql中表有別名,則必須使用表的...