본문 바로가기

sql_tuning

2-1. 인덱스 엑세스 방법

728x90
반응형

1 마지막 문제답으로

merge 인덱스 소개:

select /*+ rowid(e) use_nl(v e) */

         e.ename, e.sal, e.job, e.deptno

 from emp e,

         (select /*+ no_merge index_ffs(emp emp_ename) */

                 rowid as rn

               from emp

              where ename like '%EN%'

                   or   ename like '%IN%') v

where e.rowid = v.rn;

 

 

※ no_merge 힌트?

  in line view 해체하지 말아라

 

 

index 엑세스 방법 7가지

 

1. index range scan

2. index unique scan

3. index full scan

4. index fast full scan

5. index skip scan

6. index merge scan

7. index bitmap merge scan

 

 

index unique scan

"unique 인덱스를 엑세스 하는 스캔 방법"

 

*unique 인덱스의 종류 2가지

1. unique 인덱스 : 인덱스를 컬럼의 데이터가 unique 데이터인

                       경우의 생성될 인덱스

: emp 테이블에서 unique 컬럼은 empno

 

2. non  unique 인덱스: 인덱스를 컬럼의 데이터가 중복되어 있는

                            경우의  생성될 인덱스

: emp 테이블에서 non unique 컬럼은 deptno, job

 

*unique 인덱스 생성 방법 2가지

 1. 명시적 방법: 

                     create unique index emp_empno

                      on emp(empno);

 

 2. 암시적 방법:

                    primary key unique 제약을 걸면

                   자동으로 unique 인덱스가 생성.

 

*테스트

1. demoble.sqp 스크립트를 수행하시오

2. create unique index emp_empno

 on emp(empno);

 

 create index emp_sal

 on  emp(sal);

 

3. select index_name, uniqueness

 from user_indexes

where table_name = 'EMP';

 

4. 다시 demobld

5. insert into emp (empno, ename, sal)

     values (7788, 'SCOTT', 3000);

 

6. unique index 걸어보아라

create unique index emp_empno

 on emp(empno);

에러나옴. 중복키 있어서.

 

중복된 데이터가 있으면 unique 인덱스가 걸립니다.

  다시 말하면 unique 인덱스가 걸리는 컬럼은

  컬럼에 중복된 데이터가 하나도 없다는 것이다.

 

 

암시적 방법 유니크 인덱스

 

문제25. 데모벨 스크립트를 다시 돌리고,

 사원 테이블의 empno primary key 제약을 걸고

unique 인덱스가 자동으로 생성되었는지 확인하시오!

 

alter table emp

 add constraint emp_empno_pk primary key(empno);

 

select index_name, uniqueness

 from user_indexes

where table_name = 'EMP';

 

 

문제26. 위의 상황에서 이름에 non unique index 걸고

아래의 sql 수행하면 어느 컬럼의 인덱스를 사용할 인가?

 

create index emp_ename

 on emp(ename);

 

select empno, ename, sal, job

 from emp

 where empno = 7788

 and   ename = 'SCOTT';

 

 

***

non unique index = range index

            VS

unique index

 

어느 것을 타는가?

 

*오라클이 우선순위 non unique 인덱스보다

 unique 인덱스를 훨씬 높게 준다.

 

*오라클의 수행작업 우선순위

1. rowid 의한 데이터

:

:

10. full table scan

 

 

문제27. 우리반 테이블 이름에 unique 제약을 걸고

 unique 인덱스가 생성되었는지 확인하시오

 

alter table emp2

 add constraint emp2_ename_pk primary key(ename);

 

select index_name, uniqueness

from user_indexes

where table_name = 'EMP2';

 

 

문제28. 사원번호가 7788 번인 사원의 사워번호, 이름, 월급을

출력하는 sql 실행계획을 보고 index unique scan 했는지

확인하시오!

 

select empno, ename, sal

from emp

 where empno = 7788;

select empno, rowid

from emp;

range scan(=non unique) 같은 경우는 7788찾고

밑으로 스캔한다음에

rowid 넘어가는데,

 unique index 7788 찾자 마자 바로 빠져나가서

훨씬 빠르다.

unique 인덱스는 인덱스에서 건만 읽는다.

 

 

index merge scan

"데이터를 검색할

  개의 인덱스를 동시에 사용해서

  시너지 효과를 보는 스캔 방법"

 

*현업에서 많이 쓰이지 않아서

간단하게 테스트 돌리고 넘어가겠다고 하셨음.

테스트:

create index emp_job

on emp(job);

 

create index emp_deptno

on emp(deptno);

 

select empno, ename, job, deptno

 from emp

 where job ='SALESMAN',

 and deptno = 30;

 

실행계획 확인

 

 

select count(*) form emp where deptno

 

실행계획을 확인해보니 job 인덱스를 탔는데

만약 개의 인덱스를 동시에 사용하고 싶다면?

 

select /*+ and_equal (emp emp_deptno emp_job) */

      empno, ename, job, deptno

  from emp

 where job = 'SALESMAN' and deptno = 30;

 

쿼리는

안에 목차가 2개있어서 2개를 가지고

찾아내라는 명령어다.

 

하지만

emp_job 인덱스만 타고 실행한 쿼리보다

블럭수가 많다.

 

그런데

대용량 작업할 상황에 따라

각각 다르게 나온다. 봐서 알아서 쓰면 된다.

 

요즘은 merge index 쓰는 이유가

bitmap merge 훨씬 성능이 좋아서다.

 

 

index bitmap merge scan

" 개의 인덱스를 사용하는 것은 index merge scan 똑같은데,

다른 것은 인덱스를 bit 변환해서

사이즈를 줄인 다음 스캔한다는 것이 차이점이다."

 

: 앞에 목차가 10, 뒤의 목차도 10 이라고 하면

index merge scan 10, 10 두개를 같이 읽어서

테이블에 찾아갈 rowid 알아낸다면

index bitmap merge scan 10장을 1장으로 요약한다.

1, 1 개를 같이 읽어서 테이블에 찾아갈 rowid

알아낸다.

보고서 10 짜리를 1장으로 요약했다고 생각하면 된다.

 

 

테스트:

alter table emp

 modify job not null;

 

alter table emp

 modify deptno not null;

 

***not null 제약 주면 null 있나없나

   찾으려고 스캔값 늘어남.

 

select /*+ index_combine(emp emp_job emp_deptno) */

       empno, ename, job, deptno

  from emp

 where job = 'SALESMAN' and deptno = 30;

답이 나오지 않습니다 !

12c 에서 지원합니다

 

 

문제29. 아래의 sql 튜닝하시오

create index emp2_ename

on emp2(ename);

 

튜닝전:

select ename, age, major

 from emp2

 where substr (ename, 1,1 )  =  '';

 

 

튜닝후:

 SELECT /*+ index (emp2 emp_ename) */

 ename, age, major

 from emp2

 where ename LIKE '%';

 

 

 

문제30. 아래의 sql 튜닝하시오

*의외로 놓친다**

 

create  index emp2_age

on emp2(age);

 

튜닝전:

 select ename, age, major

 from emp2

 where age like '4%';

 

튜닝후:

CREATE INDEX emp2_age_func

ON EMP2(TO_CHAR(age));

 

  select /*+ index (emp2 emp2_age_func) */

         ename, age, major

 from emp2

 where age like '4%';

 

데이터 타입 맞춰주는게 무척 중요하다

나중에 빅데이터 다룰

이것만 맞춰줘도 실행시간이 많이 줄어든다.

 

****

  select /*+ index (emp2 emp2_age) */

          ename, age, major

 from emp2

 where TO_CHAR(age) like '4%';

이렇게 돌려도

access full. 이미 age 문자화 시키는게 풀작업

 

To_char 안하는게 맞지않나??

럴려고 함수인덱스쓴건데???

 

 

 

*sql trace 실행계획 확인하는 방법

 

 

문제31.(점심시간문제)

*전날 마지막 문제 참고해서*

아래의 sql 튜닝하시오

전공에 통계가 포함되어져 있는 학생들의

이름, 전공을 출력하시오!

(ename, job 인덱스 걸려있는데

Job  에만 fast full index 타게끔 하고,

2 테이블을 use_nl 조인하시오.)

 

튜닝전:

select ename, major

from epm2

where major like '%통계%';

 

 

튜닝후:

create index emp2_major

 on emp2(major);

 

select/*+ rowid(e) use_nl(v e) */

e.ename, e.major

 from emp2 e,

         (select /*+ no_merge index_ffs(emp2 emp2_major) */

           rowid as rn

               from emp2

              where major like '%통계%') v

where e.rowid = v.rn;

 

지금 전제가 인덱스2 만든거다.(ename, major)

인덱스 하나만 fast full scan 해서 뽑아내는게 목적.

 

V테이블 절에 2 인덱스 합치지 말고 풀스캔하라고

No_merge index_ffs (emp emp_major) 힌트먹이고

지정인덱스 major 이용해서 Where 조건절 설정,

 

Nested loop 조인힌트 먹이고

(힌트절에 rowid 들어가는지는 모르겠음.)

Where 절에 연결고리해서 출력.

 

 

 

 

문제32. 아래의 sql 튜닝하시오

튜닝전:

select ename, sal

 from emp

 where sal = (select max(sal)

                      from emp);

 

튜닝후:

select /*+ indesx_desc  (emp emp_sal) */

     ename, sal

 from emp

 where sal > 0

 AND ROWNUM =1 ;

 

 

 

문제33.아래의 sql 튜닝하시오

튜닝전:

select ename, hiredate

 from emp

 where hiredate = (select min(hiredate)

                                    from emp) ;

설명: 가장 먼저 입사한 사원의

      이름과 입사일을 출력하는 문제인데

     위의 sql emp 2 엑세스 하고 있는

     악성 sql 이다.

     그래서 인덱스를 통해서 데이터를 엑세스 하게끔해서

      emp 1번만 엑세스 하게 하려면?

 

튜닝후:

create index emp_hiredate_func

on emp(to_char(hiredate) );

 

select /*+ index_asc (emp emp_hiredate_func) */

       ename, hiredate

 from emp

 where hiredate < to_date('9999/12/31', 'rrrr/mm/dd')

 and

 rownum = 1;

 

 

 

문제34. 아래의 sql 튜닝하시오

튜닝전:

select ename, sal

 from emp e

 where sal > (select avg(Sal)

                        from emp s

                       where s.deptno = e.deptno);

 

튜닝후:

 SELECT e.ename, e.sal

  FROM EMP e,

       (SELECT deptno, AVG(sal)평균

            FROM EMP

            GROUP BY deptno) ee    

WHERE e.deptno = ee.deptno

AND sal > 평균

ORDER BY ename;

블럭수 6

 

 

SELECT ename, sal

FROM (

SELECT ename, sal, AVG(sal) OVER(PARTITION  BY deptno) 평균

FROM emp)

WHERE sal > 평균 ;

블럭수 3

 

 

 

문제35. 아래의 sql 튜닝하시오

 

튜닝전:

select ename, sal, e.job

      from emp e

   where 4 < (select count(*)

                          from emp s

                          where s.job = e.job);

 

 

튜닝후:

 

우용답

 Select ename, sal,job

From (select ename,sal,job, count(*) over (partition by job ) coun

From emp)

Where coun >= 4;

 

 

SELECT ename, sal, e. job

 FROM EMP e,

     (SELECT job, COUNT(*)직업수

       FROM EMP

        GROUP BY job) ee

WHERE e.job = ee.job

AND 직업수 >= 4 ;

                

 

 

 

문제36. 아래의 sql 튜닝하시오

튜닝전:

 select job, sum(sal)

  from emp

  group by job

 union

 select null as job, sum(Sal)

 from emp;

 

튜닝후:

select job, sum(sal)

from emp

 group by grouping sets(job, () );

또는 rollup

 

 

 

 

expand_gset_to_union

문제37. 아래의 sql union all 변경하시오

 

튜닝전:

select deptno, job, avg(sal)

from emp

 group by grouping sets( (deptno), (job) );

139블럭

 

 

튜닝시도

select /*+ expand_gset_to_union */

deptno, job, avg(sal)

from emp

 group by grouping sets( (deptno), (job) );

블럭수 54개로 줄어든다.

 

설명: expand_gset_to_union 힌트는?

 오라클 옵티마이져에게 sql 네가 union all

 작성해라 라고 명령을 내리는 힌트

 

 

튜닝후:

select deptno, null, avg(sal)

from emp

group by deptno

union all

select null, job, avg(sal)

from emp

group by job;

44블럭

Expand_gset_to_union 이라는 힌트쓰면

Union all 써서 일일이 쿼리 안짜도 .

 

 

 

728x90
반응형

'sql_tuning' 카테고리의 다른 글

5. 파티셔닝  (0) 2019.04.02
4. 서브쿼리 튜닝  (0) 2019.04.02
3. 조인 튜닝  (0) 2019.04.02
2. 인덱스 튜닝  (0) 2019.04.02
1. sql 튜닝이란 무엇이고 왜 배워야 하는가?  (0) 2019.04.02