Oracle怎麼對IN子查詢使用綁定變量(轉)

在實際使用中,經常會有帶in的子查詢,如where id in (1,2,3)這樣的情況,但是如果很多這樣的語句在數據庫中出現,將引起數據庫的大量硬解析與共享池SQL碎片。所以,在實際應用中,可以採用其他方法,將這些in list給綁定起來。

如果需要綁定in list,首先,需要創建兩個類型(type):

針對數據類型的

CREATE OR REPLACE TYPE NUMTABLETYPE as table of number;

針對字符串類型的(每個list的單元大小不要超過1000字節)

create or replace type vartabletype as table of varchar2(1000);

然後創建兩個相關的函數

數字列表函數
create or replace function str2numList( p_string in varchar2 ) return numTableType
as
v_str long default p_string || ‘,‘;
v_n number;
v_data numTableType := numTableType();
begin
loop
v_n := to_number(instr( v_str, ‘,‘ ));
exit when (nvl(v_n,0) = 0);
v_data.extend;
v_data( v_data.count ) := ltrim(rtrim(substr(v_str,1,v_n-1)));
v_str := substr( v_str, v_n+1 );
end loop;
return v_data;
end;

字符列表函數
create or replace function str2varList( p_string in varchar2 ) return VarTableType
as
v_str long default p_string || ‘,‘;
v_n varchar2(2000);
v_data VarTableType := VarTableType();
begin
loop
v_n :=instr( v_str, ‘,‘ );
exit when (nvl(v_n,0) = 0);
v_data.extend;
v_data( v_data.count ) := ltrim(rtrim(substr(v_str,1,v_n-1)));
v_str := substr( v_str, v_n+1 );
end loop;
return v_data;
end;

創建之後,我們就可以採用如下的方式來使用in list的綁定了。如可以採用如下的三種方案

SELECT /*+ ordered use_nl(a,u) */ id, user_id, BITAND(promoted_type,4) busauth
from table(STR2NUMLIST(:bind0)) a,
bmw_users u
where u.user_id = a.column_value;

SELECT /*+ leading(a) */ id, user_id, BITAND(promoted_type,4) busauth
from bmw_users u where user_id in
(select * from table(STR2NUMLIST(:bind0)) a);

SELECT /*+ index(bmw_users UK_BMW_USERS_USERID) */ id, user_id
from bmw_users where user_id in
(SELECT * FROM THE (SELECT CAST(STR2NUMLIST(:bind0) AS NUMTABLETYPE)
FROM dual) WHERE rownum<1000); 在如上的方案中,以上語句中的hint提示,是爲了穩定執行計劃,防止Oracle對in list的錯誤估計而導致走hash連接。一般建議採用第一種方法,比較簡單可靠並且可以指定穩定的計劃。但是要求數據庫的版本比較高,在老版本中(8i),可能只能採用第三種方法。總的來說,1、2兩種方法比3要少6個邏輯讀左右。如:SQL> SELECT /*+ ordered use_nl(a,u) */ id, user_id
2 from table(STR2NUMLIST(’1,2,3′)) a,
3 bmw_users u
4* where u.user_id = a.column_value

Execution Plan
———————————————————-
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3279 Card=8168 Bytes =334888)
1 0 NESTED LOOPS (Cost=3279 Card=8168 Bytes=334888)
2 1 COLLECTION ITERATOR (PICKLER FETCH) OF ‘STR2NUMLIST’
3 1 TABLE ACCESS (BY INDEX ROWID) OF ‘BMW_USERS’ (Cost=1 Card=1 Bytes=39)
4 3 INDEX (UNIQUE SCAN) OF ‘UK_BMW_USERS_USERID’ (UNIQUE)

Statistics
———————————————————-
0 recursive calls
0 db block gets
10 consistent gets
0 physical reads
0 redo size
……

SQL> SELECT /*+ index(bmw_users UK_BMW_USERS_USERID) */ id, user_id
2 from bmw_users where user_id in
3* (SELECT * FROM THE (SELECT CAST(STR2NUMLIST(’1,2,3′) AS NUMTABLETYPE) FROM dual) WHERE rownum<1000)

Execution Plan
———————————————————-
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=430 Card=999 Bytes=51948)
1 0 NESTED LOOPS (Cost=430 Card=999 Bytes=51948)
2 1 VIEW OF ‘VW_NSO_1′ (Cost=11 Card=999 Bytes=12987)
3 2 SORT (UNIQUE)
4 3 COUNT (STOPKEY)
5 4 COLLECTION ITERATOR (PICKLER FETCH) OF ‘STR2NUMLIST’
6 5 TABLE ACCESS (FULL) OF ‘DUAL’ (Cost=2 Card=82)
7 1 TABLE ACCESS (BY INDEX ROWID) OF ‘BMW_USERS’ (Cost=1 Card=1 Bytes=39)
8 7 INDEX (UNIQUE SCAN) OF ‘UK_BMW_USERS_USERID’ (UNIQUE)

Statistics
———————————————————-
0 recursive calls
0 db block gets
16 consistent gets
0 physical reads
0 redo size
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章