문제581. c##scott 유져가 소유하고 있는 인덱스 리스트를 확인하시오 !
select *
from user_indexes;
select index_name, table_name, uniqueness
from user_indexes
where table_name ='EMP';
문제582. 아래의 SQL을 튜닝하시오 !
튜닝전: select ename, hiredate
from emp
where to_char(hiredate,'RR/MM/DD') = '81/12/11';
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 32 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| EMP | 2 | 32 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
튜닝후: select ename, hiredate
from emp
where hiredate = to_date('81/12/11','RR/MM/DD');
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 32 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| EMP | 2 | 32 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | EMP_HIREDATE | 2 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------
설명: where 절에 인덱스 컬럼을 가공하면 인덱스를 사용할 수 없고 full table scan 을 하게 됩니다.
문제583. 아래의 SQL을 튜닝하시오 ! ( 인덱스의 구조를 이해하기 위한 문제 )
튜닝전 : select ename, sal
from emp
order by sal asc ;
순서를 정렬하는 것이 성능을 떨어뜨린다. pmom **PGA라는 것이 정렬**을 한다...
정렬을 메모리 공간(PGA)이 협소해서 잘못하기 때문에 디스크로 내려서
정렬하고 왔다갔다 하면서 DISK I/O가 발생한다.
하나의 세션에서 사용할 수 있는 PGA의 영역이 크지 않다.
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 280 | 4 (25)| 00:00:01 |
| 1 | SORT ORDER BY | | 14 | 280 | 4 (25)| 00:00:01 | --------> 성능이 저하된다.
| 2 | TABLE ACCESS FULL| EMP | 14 | 280 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
튜닝후 : select /*+ index_asc(emp emp_sal) */ ename, sal
from emp
where sal >=0 ;
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 280 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| EMP | 14 | 280 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | EMP_SAL | 14 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
설명: **이미 인덱스는 데이터를 정렬해서 저장하고 있으므로 인덱스에서
정렬된 데이터를 읽어오는게 더 성능이 좋습니다.**
order by 를 수행하는것보다 더 성능이 좋습니다.
1. 힌트 /*+ index_asc(테이블명 인덱스 이름) */ : 인덱스를 ascending 하게 스캔
2. 힌트 /*+ index_desc(테이블명 인덱스 이름) */ : 인덱스를 descending 하게 스캔
문제584. 아래의 SQL을 튜닝하시오 !
튜닝전: select ename, job, sal
from emp
where job='SALESMAN'
order by sal desc ;
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 104 | 3 (34)| 00:00:01 |
| 1 | SORT ORDER BY | | 4 | 104 | 3 (34)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMP | 4 | 104 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_JOB | 4 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
튜닝후: select /*+ index_desc(emp emp_sal) */ ename, job, sal
from emp
where sal >= 0 and job='SALESMAN';
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 104 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID BATCHED| EMP | 4 | 104 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN DESCENDING | EMP_SAL | 13 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
문제585. 아래의 SQL을 튜닝하시오 !
튜닝전: select ename, hiredate
from emp
order by hiredate desc ;
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 224 | 4 (25)| 00:00:01 |
| 1 | SORT ORDER BY | | 14 | 224 | 4 (25)| 00:00:01 |
| 2 | TABLE ACCESS FULL| EMP | 14 | 224 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
튜닝후: select /*+ index_desc(emp emp_hiredate) */ ename, hiredate
from emp
where hiredate < to_date('9999/12/31','RRRR/MM/DD');
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 13 | 208 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| EMP | 13 | 208 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN DESCENDING | EMP_HIREDATE | 13 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------
**※ where 절에 검색하고자 하는 컬럼명이 반드시 있어야 관련된 힌트가 작동합니다.
※ 인덱스의 데이터를 스캔하기 위해 WHERE 절에 해당 인덱스 컬럼이
있어야하는데 인덱스의 데이터를 읽어오기 위한 조건들**
1. 문자 > ' '
2. 숫자 >= 0
3. 날짜 < to_date('9999/12/31', 'RRRR/MM/DD')
※ 인덱스의 구조를 위한 SQL튜닝 방법 :
1. where 절의 좌변을 가공하지 말아라
2. order by 절 대신에 인덱스를 이용해라 !
1. 수동으로 : create index emp_deptno
on emp(deptno);
2. 자동으로 : primary key 제약이나 unique 제약을 걸면
제약(contraint)은 테이블의 데이터의 품질을 높이기 위해서
반드시 필요한 db 기능입니다. **primary key 제약을 생성한 컬럼은
중복된 데이터와 null 값이 입력안됩니다.**
alter table emp
add constraint emp_empno_pk primary key(empno);
insert into emp(empno, ename, sal)
values( null, 'jane', 4000) ;
ORA-01400: NULL을 ("C##SCOTT"."EMP"."EMPNO") 안에 삽입할 수 없습니다
insert into emp(empno, ename, sal )
values( 7788, 'jack', 5000);
ORA-00001: 무결성 제약 조건(C##SCOTT.EMP_EMPNO_PK)에 위배됩니다
select index_name, uniqueness
from user_indexes
where table_name='EMP';
EMP_EMPNO_PK UNIQUE <- 중복된 data 가 없어야 걸리는 제약
중복된 data 가 없어야 생선되는 인덱스
alter table emp17
add constraint emp17_ename_un unique(ename);
select index_name, uniqueness
from user_indexes
where table_name='EMP17';
문제586. 우리반 테이블에서 이름이 김동휘 학생의 이름과 나이와 주소를
출력하고 그 쿼리문의 실행계획을 확인하시오 !
explain plan for
select ename, age, address
from emp17
where ename='김동휘';
select * from table(dbms_xplan.display);
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 33 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP17 | 1 | 33 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP17_ENAME_PK | 1 | | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
select ename, rowid
from emp17
where ename > ' ';
김기찬 AAASQ/AAHAAAACnAAD
김동휘 AAASQ/AAHAAAACnAAM
김정명 AAASQ/AAHAAAACnAAC
김준혁 AAASQ/AAHAAAACnAAP
김지혜 AAASQ/AAHAAAACnAAI
김하람 AAASQ/AAHAAAACnAAG
김희선 AAASQ/AAHAAAACnAAT
서원길 AAASQ/AAHAAAACnAAH
송현민 AAASQ/AAHAAAACnAAJ
신예환 AAASQ/AAHAAAACnAAA
안초룡 AAASQ/AAHAAAACnAAQ
양희림 AAASQ/AAHAAAACnAAL
윤성해 AAASQ/AAHAAAACnAAF
윤영민 AAASQ/AAHAAAACnAAB
이상화 AAASQ/AAHAAAACnAAS
이승휘 AAASQ/AAHAAAACnAAE
이해인 AAASQ/AAHAAAACnAAK
이효진 AAASQ/AAHAAAACnAAO
정범우 AAASQ/AAHAAAACnAAR
최서우 AAASQ/AAHAAAACnAAN
설명: unique 인덱스는 이름의 중복된 데이터가 없음이 확실히 보장된
인덱스이므로 김동휘 하나의 인덱스 행만 검색하고 바로 테이블 엑세스를
하러 가고 끝납니다. 그러나 non unique 인덱스이면 그 다음행인 김정명
행을 엑세스 합니다.
그래서 옵티마이져가 아래와 같은 SQL이 있고 2개의 인덱스가 있으면
unique 인덱스를 더 선호합니다.
select ename, age, address
from emp17
where age= 33 and ename='김동휘';
↑ ↑
create index emp17_age alter table emp17
on emp17(age) ; add constraint emp17_un unique(ename);
문제587. 여러분 자리에 옵티마이져가 똑똑한 옵티마이져인지 확인하시오 !
create index emp17_age
on emp17(age);
alter table emp17
add constraint emp17_un unique(ename);
확인 한번 해보세요.
select index_name, table_name, uniqueness
from user_indexes; -> 확인
explain plan for
select ename, age, address
from emp17
where age= 33 and ename='김동휘';
select * from table(dbms_xplan.display);
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 33 | 1 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP17 | 1 | 33 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP17_UN | 1 | | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
※ 옵티마이져는 더 좋은 인덱스를 엑세스를 하는데 만약 덜 좋은 인덱스를
엑세스 했다면 dba 가 힌트를 줘서 튜닝을 해주면 됩니다.
문제588. 아래의 SQL의 실행계획이 emp17_age 인덱스를 엑세스 하도록
힌트를 주고 실행계획을 확인하시오 !
select **/*+ index(emp17 emp17_age) */** ename, age, address
from emp17
where age= 33 and ename='김동휘';
-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 33 | 2 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID BATCHED| EMP17 | 1 | 33 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | EMP17_AGE | 2 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------
설명: 여러개의 인덱스중에 특정 인덱스를 사용하게 하고 싶을 때
아래의 index 힌트를 이용합니다.
/*+ index( 테이블명 인덱스이름) */
* 데이터의 값이 unique 한지 unique 하지 않은지에 따라 2가지 ?
1. unique index : primary key 제약 또는 unique 제약을 걸었을때
alter table emp17
add constraint emp17_un unique(empno)
primary key(empno)
또는
create unique index emp17_empno
on emp17(empno);
2. non unique index : create index emp_job
on emp(job);
1. 단일 컬럼 인덱스 : 인덱스를 구성하는 컬럼의 갯수 1개
문법: create index emp_sal
on emp(sal);
2. 결합 컬럼 인덱스 : 인덱스를 구성하는 컬럼의 갯수가 2개 이상
문법 : create index emp_job_sal
on emp(job, sal) ;
SQL> @init_emp.sql <--- 이 스크립트를 수행하면 emp 이 테이블이
drop 되어서 emp 테이블과 연관된 인덱스들도 다 drop 됩니다.
select *
from user_indexes
where table_name='EMP';
예제. 아래의 결합 컬럼 인덱스를 생성하고 이 결합 컬럼 인덱스의 구조를 확인
하시오 !
create index emp_job_sal
on emp( job, sal );
예제. 위의 결합 컬럼이 인덱스의 구조를 확인하시오 !
인덱스 구조 : 1. 컬럼값 + rowid
2. 컬럼값이 ascending 하게 정렬되어있습니다.
select job, sal, rowid
from emp
where job > ' ';
JOB SAL ROWID
------------------ ---------- ------------------
ANALYST 3000 AAASUvAAHAAAYZtAAJ
ANALYST 3000 AAASUvAAHAAAYZtAAL
CLERK 800 AAASUvAAHAAAYZtAAK
CLERK 950 AAASUvAAHAAAYZtAAH
CLERK 1100 AAASUvAAHAAAYZtAAM
CLERK 1300 AAASUvAAHAAAYZtAAN
MANAGER 2450 AAASUvAAHAAAYZtAAC
MANAGER 2850 AAASUvAAHAAAYZtAAB
MANAGER 2975 AAASUvAAHAAAYZtAAD
PRESIDENT 5000 AAASUvAAHAAAYZtAAA
SALESMAN 1250 AAASUvAAHAAAYZtAAE
SALESMAN 1250 AAASUvAAHAAAYZtAAI
SALESMAN 1500 AAASUvAAHAAAYZtAAG
SALESMAN 1600 AAASUvAAHAAAYZtAAF
drop index emp_job_sal
SQL > @init_emp.sql
create table emp_num
as
select empno, ename, sal
from emp
where 1 = 2 ;
create sequence seq5
increment by 1
start with 1
maxvalue 10000
nocycle
cache 20;
insert into emp_num
select seq5.nextval, ename, sal
from emp;
select * from emp_num;
문제589. emp 테이블의 job 컬럼에 인덱스를 생성하시오 !
( 인덱스 이름은 emp_job 으로 하세요 )
create index emp_job
on emp(job);
문제590. 직업이 CLERK 인 사원들의 직업과 월급을 출력하는 쿼리문의
실행계획을 확인하시오 !
explain plan for
select job, sal
from emp
where job='CLERK';
select * from table(dbms_xplan.display);
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 76 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| EMP | 4 | 76 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | EMP_JOB | 4 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
직업이 CLERK인 사원을 찾는데, 직업 뿐만아니라 sal도 찾아야 되기 때문에 index 뿐만 아니라
table ACCESS도 필수적으로 이루어 져야 한다.
JOB ROWID
------------------ ------------------
ANALYST AAASUyAAHAAAYZ9AAJ
ANALYST AAASUyAAHAAAYZ9AAL
CLERK AAASUyAAHAAAYZ9AAH
CLERK AAASUyAAHAAAYZ9AAK
CLERK AAASUyAAHAAAYZ9AAM
CLERK AAASUyAAHAAAYZ9AAN
MANAGER AAASUyAAHAAAYZ9AAB
MANAGER AAASUyAAHAAAYZ9AAC
MANAGER AAASUyAAHAAAYZ9AAD
PRESIDENT AAASUyAAHAAAYZ9AAA
SALESMAN AAASUyAAHAAAYZ9AAE
SALESMAN AAASUyAAHAAAYZ9AAF
SALESMAN AAASUyAAHAAAYZ9AAG
SALESMAN AAASUyAAHAAAYZ9AAI
ROWID JOB SAL
------------------ ------------------ ----------
AAASUyAAHAAAYZ9AAA PRESIDENT 5000
AAASUyAAHAAAYZ9AAB MANAGER 2850
AAASUyAAHAAAYZ9AAC MANAGER 2450
AAASUyAAHAAAYZ9AAD MANAGER 2975
AAASUyAAHAAAYZ9AAE SALESMAN 1250
AAASUyAAHAAAYZ9AAF SALESMAN 1600
AAASUyAAHAAAYZ9AAG SALESMAN 1500
AAASUyAAHAAAYZ9AAH CLERK 950
AAASUyAAHAAAYZ9AAI SALESMAN 1250
AAASUyAAHAAAYZ9AAJ ANALYST 3000
AAASUyAAHAAAYZ9AAK CLERK 800
AAASUyAAHAAAYZ9AAL ANALYST 3000
AAASUyAAHAAAYZ9AAM CLERK 1100
AAASUyAAHAAAYZ9AAN CLERK 1300
설명: 위의 SQL의 실행계획은 JOB 에 대한 DATA 는 emp_job 에 있지만
select 절에서 요구하는 sal 에 대한 data 는 emp_job 에 없으므로
emp 테이블을 엑세스 하러 가야 하는 실행계획이 나왔습니다.
만약 인덱스에 sal 까지도 다 구성했으면 테이블 엑세스하러 갈 필요가
없었을 것 입니다.
문제591. emp 테이블에 job 과 sal 에 다음과 같이 결합 컬럼 인덱스를
생성하시오 !
create index emp_job_sal
on emp(job, sal);
문제592. 아래의 SQL의 실행계획을 다시 확인하시오 !
explain plan for
select job, sal
from emp
where job='CLERK';
select * from table(dbms_xplan.display);
1. emp_job
2. emp_job_sal
둘중에 어떤 인덱스를 탈지 궁금하다 -> 당연히 아래와 같이 emp_job_sal을 탄다!!
(table access를 하지 않고 그냥 인덱스만 읽고 끝난다! 속도가 더 빠르다!)
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 76 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| EMP_JOB_SAL | 4 | 76 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------
설명: emp_job_sal 결합 컬럼 인덱스에서 job 과 sal 에 대한 data 를
다 얻어냈기 때문에 emp 테이블을 엑세스 하지 않는 실행계획이
나왔습니다.
인덱스 구조 확인
select job, sal, rowid
from emp
where job > ' ';
JOB SAL ROWID
------------------ ---------- ------------------
ANALYST 3000 AAASUyAAHAAAYZ9AAJ
ANALYST 3000 AAASUyAAHAAAYZ9AAL
CLERK 800 AAASUyAAHAAAYZ9AAK
CLERK 950 AAASUyAAHAAAYZ9AAH
CLERK 1100 AAASUyAAHAAAYZ9AAM
CLERK 1300 AAASUyAAHAAAYZ9AAN
MANAGER 2450 AAASUyAAHAAAYZ9AAC
MANAGER 2850 AAASUyAAHAAAYZ9AAB
MANAGER 2975 AAASUyAAHAAAYZ9AAD
PRESIDENT 5000 AAASUyAAHAAAYZ9AAA
SALESMAN 1250 AAASUyAAHAAAYZ9AAE
SALESMAN 1250 AAASUyAAHAAAYZ9AAI
SALESMAN 1500 AAASUyAAHAAAYZ9AAG
select empno, ename, sal, job, deptno
from emp
where empno = 7788;
create index emp_idx7
on emp(empno, ename, sal, job, deptno);
문제593. emp 테이블과 관련된 인덱스를 조회하시오 !
select index_name, uniqueness
from user_indexes
where table_name = ‘EMP’;
문제594. 아래의 SQL을 튜닝하시오 !
튜닝전 : select ename, job, sal
from emp
where job='CLERK'
order by sal desc;
튜닝후: select /+ index_desc(emp emp_job_sal) / ename, job, sal
from emp
where job='CLERK' and sal > ‘ ‘; --> 결합컬럼의 index에서 where 절에 job 이 잘 있으므로.. 쓸필요가 없다. 힌트과 검색조건을 다 썼기 때문에..
문제595. deptno 와 sal 을 결합 컬럼 인덱스로 생성하시오 !
( 인덱스 이름은 emp_deptno_sal 로 하시오 )
create index emp_deptno_sal
on emp( deptno, sal );
문제596. emp_deptno_sal 인덱스의 구조를 확인하시오 !
**인덱스의 구조 : 1. 컬럼값 + rowid
2. 컬럼값이 ascending 하게 정렬이 됨**
select deptno, sal, rowid
from emp
where deptno >= 0;
DEPTNO SAL ROWID
---------- ---------- ------------------
10 1300 AAASUyAAHAAAYZ9AAN
10 2450 AAASUyAAHAAAYZ9AAC
10 5000 AAASUyAAHAAAYZ9AAA
20 800 AAASUyAAHAAAYZ9AAK
20 1100 AAASUyAAHAAAYZ9AAM
20 2975 AAASUyAAHAAAYZ9AAD
20 3000 AAASUyAAHAAAYZ9AAJ
20 3000 AAASUyAAHAAAYZ9AAL
30 950 AAASUyAAHAAAYZ9AAH
30 1250 AAASUyAAHAAAYZ9AAE
30 1250 AAASUyAAHAAAYZ9AAI
30 1500 AAASUyAAHAAAYZ9AAG
30 1600 AAASUyAAHAAAYZ9AAF
30 2850 AAASUyAAHAAAYZ9AAB
문제597. 아래의 SQL을 튜닝하시오 ! ( order by 절을 사용하지 말고 수행하시오)
emp_deptno_sal 인덱스를 활용
튜닝전 : select ename, deptno, sal
from emp
where deptno = 20
order by sal desc;
튜닝후:
explain plan for
select /+ index_desc( emp emp_deptno_sal ) / ename, deptno, sal
from emp
where deptno = 20;
select * from table(dbms_xplan.display);
1. 테이블의 크기가 클때 :
EMP 테이블 처럼 작은 테이블은 인덱스가 필요없습니다.
인덱스 없이도 검색속도가 빠릅니다.
2. null 값이 많은 컬럼에 인덱스를 걸면 좋다.
인덱스 구성시 null 값은 구성되지 않습니다. 책에 빈페이지는 목차에 구성 안됩니다.
3. where 절에 자주 검색되는 컬럼에 인덱스를 걸어줘야 합니다.
select empno, ename, sal
from emp
where ename='SCOTT';
select job, deptno, ename
from emp
where ename='ALLEN';
4. 검색하려는 데이터의 행이 전체 테이블의 2~4% 미만인 컬럼에
인덱스를 거는게 유용하다.
1. where 절에 자주 검색되지 않는 컬럼
2. 테이블이 작거나 검색하는 행이 테이블 전체의 2~4% 이상의 컬럼
3. **자주 갱신되는 컬럼(★) (특히 insert)**
테이블의 데이터를 변경하면 인덱스도 같이 변경해줘야합니다.
책의 내용을 변경하면 목차도 다시 변경해야합니다.
그런데 책은 그냥 변경하면 간단하지만 목차는 ㄱㄴㄷ 순서이기 때문에
변경할 때 시간이 많이 걸립니다.
인덱스가 있는 테이블에 insert, update 를 하면 insert, update 속도가 느려집니다
4. 인덱스화 된 열이 컬럼에 표현식으로 사용되는 경우 (가공이 된 경우)
select ename, sal
from emp
where sal * 12 = 36000;
문제598. 인덱스가 생성되어있는 테이블과 생성되어있지 않은 테이블에
대량의 데이터를 insert 할때 속도를 확인하시오 !
다음 2개의 테이블을 생성합니다.
create table sales_no_index
as
select * from sales where 1 = 2; ---> 구조만 만든다!!!!
create table sales_with_index
as
select * from sales where 1 = 2 ;
위의 2개의 테이블중에 sales_with_index 테이블에만 인덱스를 생성하시오
create index sales_index_1
on sales_with_index(amount_sold, promo_id);
아래와 같이 대량의 데이터를 2개 테이블에 각각 입력하고 속도를 비교하시오!
set timing on
insert into sales_no_index
select *
from sales;
경 과: 00:00:00.57
insert into sales_with_index
select *
from sales;
경 과: 00:00:01.84
설명: 테이블에 인덱스가 있으면 insert 가 느려집니다.
문제599. emp 테이블에 관련된 인덱스가 무엇인지 조회하시오 !
select index_name
from user_indexes
where table_name='EMP';
문제600. emp 테이블과 관련된 모든 인덱스를 다 삭제하시오 !
drop index emp_job;
drop index emp_job_sal;
drop index emp_idx7;
drop index emp_deptno_sal;
설명: emp 테이블을 삭제하면 emp 테이블과 관련된 인덱스들도 다 삭제 됩니다.
동의어 ? 특정 객체에 대한 다른 이름
c##scott (dba) <-- 테이블을 만든 사람은 해당 테이블에 drop 권한도 있습니다.
emp
dept
c##smith ( 개발자 ) <-- emp 와 dept 테이블에 대해서 select , update ,
insert 정도의 권한만 줘야합니다.
문제601. c##scott 유져에서 c##smith 유져를 만들고 접속할 수 있는 권한을
부여하고 c##smith 유져로 접속하시오 !
create user c##smith
identified by tiger ;
grant connect to c##smith;
--> select * from c##scott.emp; 유저명이 노출된다.
grant select on emp to c##smith;
create public synonym emp
for c##scott.emp;
설명: 개발 dba 가 emp 테이블을 생성했으면 위와 같이 synonym 도 생성합니다.
synonym 을 만들어야 c##smith 유져가 emp 테이블 select 할때
테이블명 앞에 c##scott 을 접두어로 안붙여도 되기 때문입니다
문제602. c##smith 유져가 다음과 같이 dept 테이블과 saglrade 테이블을
조회할 수 있게 하시오 !
select from dept;
select from salgrade;
답:
grant select on dept to c##smith;
grant select on salgrade to c##smith;
create public synonym dept for c##scott.dept;
create public synonym salgrade for c##scott.salgrade;
문제603. 시너님을 생성하는데 employees 를 e 로 생성하시오 !
설명: c##scott 만 사용한 시너님이면 public 을 안 써도 됩니다.
create synonym e
for employees;
select * from e;
설명: 별도의 테이블이 생성되는게 아니라 employees 테이블에 대한 다른 이름이
생성되는것 입니다.
※ 개발dba 로 일할때 시너님 생성 tip
hr 계정이 가지고 있는 모든 테이블들을 c##smith 유져가 select 할 수 있게 하시오
grant select on dept to c##smith;
grant select on salgrade to c##smith;
:
create public synonym dept for c##scott.dept;
create public synonym salgrade for c##scott.salgrade;
:
예제1. hr 계정이 소유하고 있는 테이블 리스트를 확인하시오 !
select table_name
from dba_tables
where owner='HR';
예제2. hr 계정의 7개의 테이블을 select 할 수 있는 권한을 c##smith 에게
부여하는 스크립트를 생성하시오 !
select 'grant select on hr.' || table_name || ' to c##smith; '
from dba_tables
where owner='HR';
grant select on hr.REGIONS to c##smith;
grant select on hr.COUNTRIES to c##smith;
grant select on hr.LOCATIONS to c##smith;
grant select on hr.DEPARTMENTS to c##smith;
grant select on hr.JOBS to c##smith;
grant select on hr.EMPLOYEES to c##smith;
grant select on hr.JOB_HISTORY to c##smith;
예제3. 이번에는 public synonym 을 생성하시오 !
select ' create public synonym ' || table_name || ' for hr.' || table_name || ';'
from dba_tables
where owner='HR';
create public synonym REGIONS for hr.REGIONS;
create public synonym COUNTRIES for hr.COUNTRIES;
create public synonym LOCATIONS for hr.LOCATIONS;
create public synonym DEPARTMENTS for hr.DEPARTMENTS;
create public synonym JOBS for hr.JOBS;
create public synonym EMPLOYEES for hr.EMPLOYEES;
create public synonym JOB_HISTORY for hr.JOB_HISTORY;
문제604. employees 시너님을 삭제하시오 !
drop public synonym employees;
▣ 100 실수로 지운 데이터 복구하기 2(FLASHBACK TABLE)
▣ 101 실수로 지운 데이터 복구하기 3(FLASHBACK DROP)
▣ 102 실수로 지운 데이터 복구하기 4(FLASHBACK VERSION QUERY)
▣ 103 실수로 지운 데이터 복구하기 5(FLASHBACK TRANSACTION QUERY)
FUND1 → sg2 p.80
1. primary key : 중복된 data 와 null을 허용하지 못하게 막는 제약
2. unique : 중복된 data 를 허용하지 못하게 막는 제약
3. not null : null 값을 허용하지 못하게 막는 제약
4. check : 지정된 data 만 입력되고 수정될 수 있도록 막는 제약
5. foreign key : 자식키에 해당하는 컬럼에 거는 제약
오늘의 마지막 문제를 풀기위한 환경을 다음과 같이 구성합니다.
명령 프롬프트창 열고 @init_emp.sql 를 돌려주세요 !
문제605. 사원 테이블의 월급이 인덱스를 걸고 아래의 SQL의 MAX 함수
사용하지 말고 결과를 출력하시오 !
( order by 뿐만 아니라 max와 min 은 정렬작업이 내부적으로 발생
하므로 max 를 쓰지 말고 인덱스를 활용하게 해야합니다.)
create index emp_sal on emp(sal);
튜닝전 : select max(sal)
from emp;
튜닝후: select /+ index_desc( emp emp_sal) / sal
from emp
where sal >= 0 and rownum = 1;
문제606. (오늘의 마지막 문제) 아래의 SQL을 튜닝하시오 !
튜닝전: select /+ gather_plan_statistics / ename, sal
from emp
where sal = ( select max(sal)
from emp );
SELECT * FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
버퍼의 갯수 : 3개
튜닝후: SQL 과 버퍼의 갯수
select /+ gather_plan_statistics index_desc(emp emp_sal) / ename, sal
from emp
where sal >= 0 and rownum = 1;
SELECT * FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));