함수기반인덱스사용이유
note
create table test_emp
as
select *
from scott.emp
where 1=0;
insert into test_emp
(empno,ename,job ,mgr ,hiredate ,sal ,comm,deptno)
select rownum empno,
initcap(substr(object_name,1,10)) ename,
substr(object_type, 1 ,9) JOB,
rownum MGR ,
created hiredate,
rownum SAL,
rownum COMM,
(mod(rownum , 4)+1)*10 DEPTNO
from all_objects
where rownum < 10000;
create index test_emp_upper_idx on test_emp (upper(ename)) ;
begin
dbms_stats.gather_table_stats
(user, 'TEST_EMP' , cascade=>true);
end;
select * from test_emp
where upper(ename) = 'KING'
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 110 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST_EMP | 2 | 110 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | TEST_EMP_UPPER_IDX | 2 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(UPPER("ENAME")='KING')
select my_function(ename)
from test_emp
where some_other_function(empno) > 10
create or replace package stats
as
cnt number default 0;
end;
create or replace
function my_soundex( p_string in varchar2 ) return varchar2
deterministic
as
l_return_string varchar2(6) default substr( p_string, 1, 1 );
l_char varchar2(1);
l_last_digit number default 0;
type vcArray is table of varchar2(10) index by binary_integer;
l_code_table vcArray;
begin
stats.cnt := stats.cnt + 1 ;
l_code_table(1) := 'BPFV';
l_code_table(2) := 'CSKGJXZ' ;
l_code_table(3) := 'DT' ;
l_code_table(4) := 'L' ;
l_code_table(5) := 'MN' ;
l_code_table(6) := 'R' ;
for i in 1 .. length(p_string)
loop
exit when (length(l_return_string) = 6) ;
l_char := upper(substr( p_string, i , 1 ) ) ;
for j in 1 .. l_code_table.count
loop
if (instr(l_code_table(j) , l_char ) > 0 and j <> l_last_digit)
then
l_return_string := l_return_string || to_char(j , 'fm9' );
l_last_digit := j ;
end if;
end loop;
end loop;
return rpad( l_return_string, 6, '0' );
end;
set autorace on explain
variable cpu number
exec :cpu := dbms_utility.get_cpu_time
select ename, hiredate
from test_emp
where my_soundex(ename) = my_soundex('Kings');
ENAME HIREDATE
---------- --------
Ku$_Chunk_ 10/03/30
Ku$_Chunk_ 10/03/30
Ku$_Chunk_ 10/03/30
Ku$_Chunk_ 10/03/30
Plan hash value: 242355602
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 100 | 1900 | 26 (16)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TEST_EMP | 100 | 1900 | 26 (16)| 00:00:01 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("MY_SOUNDEX"("ENAME")="MY_SOUNDEX"('Kings'))
set autotrace off
begin
dbms_output.put_line
( 'cpu time = ' || round((dbms_utility.get_cpu_time - :cpu)/100,2) );
dbms_output.put_line( 'function was called: '|| stats.cnt );
end;
cpu time = .5 --- 책에서는 0.44 초
function was called: 9955 --- 책에서는 9,948
Note
create index test_emp_soundex_idx on
test_emp( substr(my_soundex(ename) ,1,6))
-- 4k 테이블 스페이스 생성못함 => ORA-03249: 자동 세그먼트 공간 관리 테이블스페이스에 대한 동일 크기는 5 블록 이상이어야 함
create index emp_soundex_idx2 on
emp( my_soundex(ename) ) tablespace ts4k;
ORA-01450: maximum key length (3118) exceeded -- 책에 실린 내용