강좌
클라우드/리눅스에 관한 강좌입니다.
데이터베이스 분류

대소문자 구분없이 검색할때 인덱스 태우기

작성자 정보

  • 웹관리자 작성
  • 작성일

컨텐츠 정보

본문

대소문자 구분없이 검색할때 인덱스 태우기

 

t.gif
t.gif
대소문자 구분없이 검색하기

Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
Linux (Kernel 2.4.18-14)


어떤 사이트에서 maddog이라는 ID를 가지는 사용자를 찾는다고 하자.
다음과 같이 할 것이다.

select * from member where id='maddog';

그럼 이런 경우는 어떤가? Maddog, MadDog, maddog 등 대소문자 관계없이 찾고 싶다면?
보통 아래처럼 질의를 작성할 것이다.

select * from member where upper(ID) = upper('maddog');

제대로 된 질의로 보이는가?
뭔가 이상함을 느끼지 못한다면 당신의 사이트는 심각한 문제를 가질 수 있다.
ID컬럼에 대해 upper함수를 먹이면 ID컬럼에 걸린 인덱스를 타지 못하므로 질의성능이 상당히 떨어질 것이고 이로인해 오랫동안 SQL*Plus화면을 쳐다보고 있어야 할 것이다.

암튼 대강의 상황은 파악되었으리라.
그럼 요지는 위의 질의에 대해 인덱스를 태우게 만드는 것이라 할 수 있다.
이렇때 사용할 수 있는 것이 function-based index이다.
말그대로 인덱스된 컬럼에 대해 함수를 먹인 값을 인덱스키로 저장한다는 것이다.
이 기능은 8i부터 사용가능하다.

SQL> conn sys/xxxxxx as sysdba
연결되었습니다.

autotrace를 이용하기 위해, function based index와는 직접적인 관련은 없다
위의 질의가 인덱스를 타는지 파악하기 위해 autotrace를 사용할 것이다.
SQL> @?/sqlplus/admin/plustrce.sql
SQL>
SQL> drop role plustrace;
drop role plustrace
          *
1행에 오류:
ORA-01919: 롤 'PLUSTRACE'(이)가 존재하지 않습니다


SQL> create role plustrace;

롤이 생성되었습니다.

SQL>
SQL> grant select on v_$sesstat to plustrace;

권한이 부여되었습니다.

SQL> grant select on v_$statname to plustrace;

권한이 부여되었습니다.

SQL> grant select on v_$session to plustrace;

권한이 부여되었습니다.

SQL> grant plustrace to dba with admin option;

권한이 부여되었습니다.

SQL> set echo off

테스트할 사용자로 maddog을 만든다
SQL> create user maddog identified by maddog
  2  default tablespace users
  3  temporary tablespace temp;

SQL> grant connect, resource, plustrace, query rewrite to maddog;

권한이 부여되었습니다.

사용자 maddog으로 연결하여 member테이블을 만들고, function-based index를 생성하기 위해
테스트 데이터를 몇개 집어 넣는다.
SQL> conn maddog/maddog
SQL> create table member(id varchar(30), name varchar(30));

테이블이 생성되었습니다.

ID컬럼을 Primary key로 한다.
Primary Key컬럼은 기본적으로 B트리 Unique index가 생성된다. 즉, ID컬럼에는 인덱스가 걸린다는 것이다.
SQL> alter table member
  2  add constraint member_pk primary key(id);

테이블이 변경되었습니다.

테스트를 위해 all_objects에서 데이터를 가져와 넣는다.
다량의 데이터를 insert줄때, 아래와 같이 append힌트를 주다면 속도가 빠르다.
SQL> insert /*+ append */ into member
  2  select object_name, owner from all_objects where object_type='VIEW';

855 개의 행이 만들어졌습니다.

SQL> commit;

커밋이 완료되었습니다.

우리가 함수기반인덱스를 테스트할 때 사용할 데이터를 넣자.
SQL> insert into member values('maddog', '강명규');

1 개의 행이 만들어졌습니다.

SQL> insert into member values('Maddog','강명규');

1 개의 행이 만들어졌습니다.

SQL> insert into member values('MadDog', '강명규');

1 개의 행이 만들어졌습니다.

플랜테이블(plan_table)을 생성한다.
SQL> @?/rdbms/admin/utlxplan.sql

테이블이 생성되었습니다.

autotrace와 execution plan를 활성화하여 질의가 어떻게 돌아가는지 파악할 것이다.
SQL> set autotrace on explain
SQL> select * from member where upper(ID) = upper('maddog');

ID                             NAME
------------------------------ ------------------------------
maddog                         강명규
Maddog                         강명규
MadDog                         강명규


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (FULL) OF 'MEMBER'


ID컬럼에는 B트리 인덱스가 걸려있으나 인덱스컬럼에 대한 Operation(upper함수사용)으로 인해 FULL 테이블스캔을 하고 있음을 알 수 있다.
이것은 테이블의 모든 row를 다 뒤져봐서 maddog을 찾는다는 의미이다.
이제, function-based index기능을 사용하여 질의의 성능을 높이도록 하자.

SQL> alter session set query_rewrite_enabled=true;

세션이 변경되었습니다.

SQL> alter session set query_rewrite_integrity=trusted;

세션이 변경되었습니다.

function-based 인덱스를 생성한다.
SQL> create index member_id_idx on member(upper(id));

인덱스가 생성되었습니다.

SQL> alter session set optimizer_mode=all_rows;

세션이 변경되었습니다.

SQL> select * from member where upper(ID) = upper('maddog');

ID                             NAME
------------------------------ ------------------------------
maddog                         강명규
Maddog                         강명규
MadDog                         강명규


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=1 Card=7 Bytes=238)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'MEMBER' (Cost=1 Card=7 Bytes=238)
   2    1     INDEX (RANGE SCAN) OF 'MEMBER_ID_IDX' (NON-UNIQUE) (Cost=1 Card=3)


위에서 보듯이 동일 질의에 대해 인덱스검색이 이루어졌음을 알 수 있다.
여기에서는 시간을 재워보지 않았는데, 10만개정도의 테스트row를 만들고 SQL*PLUS상에서 set timing on을 주고 위의 질의를 테스트해보면 성능향상을 체감할 수 있을 것이다.
옵티마이저 모드를 first_rows로 변경하고 해보자. 결과는 별 차이 없다.
SQL> alter session set optimizer_mode=first_rows;

세션이 변경되었습니다.

SQL> select * from member where upper(ID) = upper('maddog');

ID                             NAME
------------------------------ ------------------------------
maddog                         강명규
Maddog                         강명규
MadDog                         강명규


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=FIRST_ROWS (Cost=1 Card=7 Bytes=238)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'MEMBER' (Cost=1 Card=7 Bytes=238)
   2    1     INDEX (RANGE SCAN) OF 'MEMBER_ID_IDX' (NON-UNIQUE) (Cost=1 Card=3)


이제, 테이블을 analyze후에 다시 해보자.
SQL> analyze table member compute statistics;

테이블이 분석되었습니다.

SQL> select * from member where upper(ID) = upper('maddog');

ID                             NAME
------------------------------ ------------------------------
maddog                         강명규
Maddog                         강명규
MadDog                         강명규


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=FIRST_ROWS (Cost=2 Card=1 Bytes=20)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'MEMBER' (Cost=2 Card=1 Bytes=20)
   2    1     INDEX (RANGE SCAN) OF 'MEMBER_ID_IDX' (NON-UNIQUE) (Cost=1 Card=1)


SQL>

위에서 보듯이, 테이블 분석후, 질의 비용이 상당히 감소했음을 알 수 있다.
function-base index를 사용하면, 주기적으로 테이블을 분석(analyze table)해주는 것이 필요함을 알 수 있다.


[대충 정리]
function based index를 사용하기 위해선

query rewrite권한이 필요하다.
옵티마이저가 CBO(Cost Based Optimize)모드에 있어야 한다.
수시로 테이블을 analyze해준다.(CBO를 사용하므로 당연히 analyze해줘야 할 것이다.)

위에서 보면 analyze전과 후의 결과가 차이가 남을 알 수 있다.
function based index를 이용한 결과에서의 실행계획은 인덱스를 타고 있음을 알 수 있다.

This article comes from dbakorea.pe.kr (Leave this line as is)

관련자료

댓글 0
등록된 댓글이 없습니다.

공지사항


뉴스광장


  • 현재 회원수 :  60,042 명
  • 현재 강좌수 :  35,846 개
  • 현재 접속자 :  92 명