Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005

rekharaghuram
from rekharaghuram More from this publisher
05.11.2015 Views

CHAPTER 11 ■ INDEXES 459 7 l_last_digit number default 0; 8 9 type vcArray is table of varchar2(10) index by binary_integer; 10 l_code_table vcArray; 11 12 begin 13 stats.cnt := stats.cnt+1; 14 15 l_code_table(1) := 'BPFV'; 16 l_code_table(2) := 'CSKGJQXZ'; 17 l_code_table(3) := 'DT'; 18 l_code_table(4) := 'L'; 19 l_code_table(5) := 'MN'; 20 l_code_table(6) := 'R'; 21 22 23 for i in 1 .. length(p_string) 24 loop 25 exit when (length(l_return_string) = 6); 26 l_char := upper(substr( p_string, i, 1 ) ); 27 28 for j in 1 .. l_code_table.count 29 loop 30 if (instr(l_code_table(j), l_char ) > 0 AND j l_last_digit) 31 then 32 l_return_string := l_return_string || to_char(j,'fm9'); 33 l_last_digit := j; 34 end if; 35 end loop; 36 end loop; 37 38 return rpad( l_return_string, 6, '0' ); 39 end; 40 / Function created. Notice in this function, we are using a new keyword, DETERMINISTIC. This declares that the preceding function, when given the same inputs, will always return the exact same output. This is needed to create an index on a user-written function. We must tell Oracle that the function is DETERMINISTIC and will return a consistent result given the same inputs. We are telling Oracle that this function should be trusted to return the same value, call after call, given the same inputs. If this were not the case, we would receive different answers when accessing the data via the index versus a full table scan. This deterministic setting implies, for example, that we cannot create an index on the function DBMS_RANDOM.RANDOM, the random number generator. Its results are not deterministic; given the same inputs, we’ll get random output. The built-in SQL function UPPER used in the first example, on the other hand, is deterministic, so we can create an index on the UPPER value of a column.

460 CHAPTER 11 ■ INDEXES Now that we have the function MY_SOUNDEX, let’s see how it performs without an index. This uses the EMP table we created earlier with about 10,000 rows in it: ops$tkyte@ORA10G> set timing on ops$tkyte@ORA10G> set autotrace on explain ops$tkyte@ORA10G> select ename, hiredate 2 from emp 3 where my_soundex(ename) = my_soundex('Kings') 4 / ENAME HIREDATE ---------- --------- Ku$_Chunk_ 10-AUG-04 Ku$_Chunk_ 10-AUG-04 Elapsed: 00:00:01.07 Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=32 Card=100 Bytes=1900) 1 0 TABLE ACCESS (FULL) OF 'EMP' (TABLE) (Cost=32 Card=100 Bytes=1900) ops$tkyte@ORA10G> set autotrace off ops$tkyte@ORA10G> set timing off ops$tkyte@ORA10G> set serveroutput on ops$tkyte@ORA10G> exec dbms_output.put_line( stats.cnt ); 19998 PL/SQL procedure successfully completed. We can see this query took over one second to execute and had to do a full scan on the table. The function MY_SOUNDEX was invoked almost 20,000 times (according to our counter), twice for each row. Let’s see how indexing the function can speed up things. The first thing we’ll do is create the index as follows: ops$tkyte@ORA10G> create index emp_soundex_idx on 2 emp( substr(my_soundex(ename),1,6) ) 3 / Index created. The interesting thing to note in this CREATE INDEX command is the use of the SUBSTR function. This is because we are indexing a function that returns a string. If we were indexing a function that returned a number or date, this SUBSTR would not be necessary. The reason we must SUBSTR the user-written function that returns a string is that such functions return VARCHAR2(4000) types. That may well be too big to be indexed—index entries must fit within about three quarters the size of a block. If we tried, we would receive (in a tablespace with a 4KB blocksize) the following:

460<br />

CHAPTER 11 ■ INDEXES<br />

Now that we have the function MY_SOUNDEX, let’s see how it performs without an index.<br />

This uses the EMP table we created earlier with about 10,000 rows in it:<br />

ops$tkyte@ORA10G> set timing on<br />

ops$tkyte@ORA10G> set autotrace on explain<br />

ops$tkyte@ORA10G> select ename, hiredate<br />

2 from emp<br />

3 where my_soundex(ename) = my_soundex('Kings')<br />

4 /<br />

ENAME HIREDATE<br />

---------- ---------<br />

Ku$_Chunk_ 10-AUG-04<br />

Ku$_Chunk_ 10-AUG-04<br />

Elapsed: 00:00:01.07<br />

Execution Plan<br />

----------------------------------------------------------<br />

0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=32 Card=100 Bytes=1900)<br />

1 0 TABLE ACCESS (FULL) OF 'EMP' (TABLE) (Cost=32 Card=100 Bytes=1900)<br />

ops$tkyte@ORA10G> set autotrace off<br />

ops$tkyte@ORA10G> set timing off<br />

ops$tkyte@ORA10G> set serveroutput on<br />

ops$tkyte@ORA10G> exec dbms_output.put_line( stats.cnt );<br />

19998<br />

PL/SQL procedure successfully completed.<br />

We can see this query took over one second to execute <strong>and</strong> had to do a full scan on the<br />

table. The function MY_SOUNDEX was invoked almost 20,000 times (according to our counter),<br />

twice for each row.<br />

Let’s see how indexing the function can speed up things. The first thing we’ll do is create<br />

the index as follows:<br />

ops$tkyte@ORA10G> create index emp_soundex_idx on<br />

2 emp( substr(my_soundex(ename),1,6) )<br />

3 /<br />

Index created.<br />

The interesting thing to note in this CREATE INDEX comm<strong>and</strong> is the use of the SUBSTR function.<br />

This is because we are indexing a function that returns a string. If we were indexing a<br />

function that returned a number or date, this SUBSTR would not be necessary. The reason we<br />

must SUBSTR the user-written function that returns a string is that such functions return<br />

VARCHAR2(4000) types. That may well be too big to be indexed—index entries must fit within<br />

about three quarters the size of a block. If we tried, we would receive (in a tablespace with a<br />

4KB blocksize) the following:

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!