怎麼對IN子查詢使用綁定變量

怎麼對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
......
.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章