I. SQL 성능 향상 가이드.

Slides:



Advertisements
Similar presentations
강사: 이종인 다우 교육원 전임강사 / 온디멘드 수석 컨설턴트 / FMG 수석 컨설턴트
Advertisements

SQL 언어 SQL.
MYSQL 설치 SQL언어 SQL언어의 활용 웹과 SQL언어와의 연동
SQL Statement Tuning e-Architecture 팀 임성욱.
Nested Queries CSED421: Database Systems Labs.
사례 1. OPTIMIZER MODE에 따른 인덱스 사용
19.(코드+년도+월)별,(코드)별,전체총액을 한번에
PARK SUNGJIN Oracle 설치 PARK SUNGJIN
Perfect! 대용량 데이터베이스 튜닝Ⅱ.
You YOungseok 데이터베이스 테이블 및 인덱스 You YOungseok.
데이터 모델링 방법론 2003년 03월.
질의어와 SQL 기본 SQL 고급 SQL 데이타의 수정 데이타 정의 언어 내장 SQL
관계 대수와 SQL.
대용량 데이터베이스 솔루션 발표자: 박보영 2007년 5월19일.
오라클 데이터베이스 성능 튜닝.
DataBase 기본 교육 신입사원용 최지철.
Database & Internet Computing Laboratory 한 양 대 학 교
다양한 예제로 쉽게 배우는 오라클 SQL 과 PL/SQL
박시우 ( 업무에 바로 쓰는 SQL 튜닝 박시우 (
Chapter 5 SQL: 확장된 질의, 주장, 트리거, 뷰.
제 5 장 인덱스 생성 및 관리.
데이터 베이스 설계 및 실습 #1 - 오라클 설치 및 SQL 기본.
SELECT 문 사원 테이블의 모든 정보를 출력하는 예제 1. 비교 연산자 SELECT 문의 형태
4장. 관계 대수와 SQL SQL 관계 데이터 모델에서 지원되는 두 가지 정형적인 언어
SQL-99: 스키마 정의, 기본제약조건, 질의어 충북대학교 구조시스템공학과 시스템공학연구실
제 09 장 데이터베이스와 MySQL 학기 인터넷비즈니스과 강 환수 교수.
7장 조인.
다양한 예제로 쉽게 배우는 오라클 SQL 과 PL/SQL
SQL 개요 SQL 개요 - SQL은 현재 DBMS 시장에서 관계 DBMS가 압도적인 우위를 차지하는 데 중요한 요인의 하나
8장 서브 쿼리.
6장 Mysql 명령어 한빛미디어(주).
오라클 데이터베이스 성능 튜닝.
MySQL 및 Workbench 설치 데이터 베이스.
요약 정보 만들기.
오라클 데이터베이스 성능 튜닝.
기본적인 SELECT문 작성.
14장 뷰.
4.2 SQL 개요 SQL 개요 SQL은 IBM 연구소에서 1974년에 System R이라는 관계 DBMS 시제품을 연구할 때 관계 대수와 관계 해석을 기반으로, 집단 함수, 그룹화, 갱신 연산 등을 추가하여 개발된 언어 1986년에 ANSI(미국 표준 기구)에서 SQL.
6장 그룹 함수.
07 그룹 함수 그룹 함수의 개념 그룹 함수의 종류 데이터 그룹 생성 HAVING 절.
09 서브쿼리(Subquery) 서브쿼리의 개념 서브쿼리의 종류 데이터베이스 실무에서 서브쿼리 사용시 주의 사항.
14 뷰(View) 뷰의 개념 뷰 관리.
SELECT empno, ename, job, sal, dname FROM emp, dept
13 인덱스 인덱스의 개념 인덱스의 구조 인덱스의 효율적인 사용 방법 인덱스의 종류 및 생성 방법 인덱스 실행 경로 확인
17강. 데이터 베이스 - I 데이터 베이스의 개요 Oracle 설치 기본적인 SQL문 익히기
MYSQL 설치 SQL언어 SQL언어의 활용 웹과 SQL언어와의 연동
SQL.
Quiz #1.
13 인덱스 인덱스의 개념 인덱스의 구조 인덱스의 효율적인 사용 방법 인덱스의 종류 및 생성 방법 인덱스 실행 경로 확인
You YoungSEok Oracle 설치 You YoungSEok
다양한 예제로 쉽게 배우는 오라클 SQL 과 PL/SQL
다양한 예제로 쉽게 배우는 오라클 SQL 과 PL/SQL
Chapter 3: Introduction to SQL
13장 무결성 제약조건.
JDBC Lecture 004 By MINIO.
JSP 게시판 구현.
View(뷰) 1 가상 테이블(Virtual Relation)
Database 중고차 매매 DB 비즈니스IT 윤동섭.
11장. GROUP BY와 HAVING 열의 그룹화 2개 이상의 열에 대한 그룹화
오라클 쿼리 문제 EMP (사원 테이블) DEPT (부서 테이블) 컬럼명 설명 EMPNO 사원번호 ENAME 사원명 JOB
기본적인 SELECT문 작성.
8장 테이블의 생성 및 변경 정인기.
SQL Tuning.
오라클 SQL 개발 가이드 ® 조 성 복 기술본부 DB기술자문팀 한국 오라클.
06. SQL 명지대학교 ICT 융합대학 김정호.
Chapter 10 데이터 검색1.
7장 테이블 조인하기.
14 뷰(View) 뷰의 개념 뷰 관리.
 6장. SQL 쿼리.
fastestslowest 실제 질의문에서 사용 타입 추천 인덱스 SELECT list Default
Presentation transcript:

I. SQL 성능 향상 가이드

1. OR OR : Index를 사용하지 못하는 경우가 있음 S Q L 개선안 SELECT a,거래분류코드, a.sum(전표매수), a.sum(건수), a.sum(금액) FROM 조작자일별상세원장 a WHERE a.국기호 = :입력국기호 AND a.거래일자 = :입력거래일자 AND a.조작자번호 = :입력조작자번호 AND ( a.과목코드 = ‘1’ or a.과목코드 = ‘2’) GROUP BY a.거래분류코드; 개선안 SELECT a,거래분류코드, a.sum(전표매수), a.sum(건수), a.sum(금액) FROM 조작자일별상세원장 a WHERE a.국기호 = :입력국기호 AND a.거래일자 = :입력거래일자 AND a.조작자번호 = :입력조작자번호 AND a.과목코드 IN (‘1’, ’2’) AND GROUP BY a.거래분류코드; SELECT a,거래분류코드, a.sum(전표매수), a.sum(건수), a.sum(금액) FROM 조작자일별상세원장 a WHERE a.국기호 = :입력국기호 AND a.거래일자 = :입력거래일자 AND a.조작자번호 = :입력조작자번호 AND a.과목코드 = ‘1’ GROUP BY a.거래분류코드; UNION ALL AND a.과목코드 = ’2’ SELECT /*+ Use_Concat */ a,거래분류코드, a.sum(전표매수), a.sum(건수), a.sum(금액) FROM 조작자일별상세원장 a WHERE a.국기호 = :입력국기호 AND a.거래일자 = :입력거래일자 AND a.조작자번호 = :입력조작자번호 AND ( a.과목코드 = ‘1’ or a.과목코드 = ‘2’) GROUP BY a.거래분류코드;

2. BETWEEN AND 범위 검색 : 인덱스의 효율적인 사용을 위해 ‘between and’ 연산 사용 S Q L SELECT a,거래분류코드, a.sum(전표매수), a.sum(건수), a.sum(금액) FROM 조작자일별상세원장 a WHERE a.국기호 = :입력국기호 AND a.거래일자 >= :입력거래일자1 AND a.거래일자 <= :입력거래일자2 AND a.조작자번호 = :입력조작자번호 AND a.과목코드 IN (‘1’, ’2’) GROUP BY a.거래분류코드; 개선안 SELECT a,거래분류코드, a.sum(전표매수), a.sum(건수), a.sum(금액) FROM 조작자일별상세원장 a WHERE a.국기호 = :입력국기호 AND a.거래일자 BETWEEN :입력거래일자1 AND :입력거래일자2 AND a.조작자번호 = :입력조작자번호 AND a.과목코드 IN (‘1’, ’2’) GROUP BY a.거래분류코드;

3. LIKE %를 문자 앞에 사용하면 인덱스를 사용하지 못 함 SELECT a.국명, a.국기호 FROM 관서 a Q L SELECT a.국명, a.국기호 FROM 관서 a WHERE a.국명 LIKE ‘%국’; 개선안 SELECT a.국명, a.국기호 FROM 관서 a WHERE a.국명 LIKE ‘서울%’;

4. JOIN 테이블 조인시 중복되는 조건이 추가되면 성능을 저하시킴 S Q L 개선안 SELECT a,거래분류코드, a.sum(전표매수), a.sum(건수), a.sum(금액) FROM 조작자일별상세원장 a, 관서 b WHERE a.국기호 = :입력국기호 AND b.국기호 = :입력국기호 AND a.국기호 = b.국기호 AND a.거래일자 BETWEEN :입력거래일자1 AND :입력거래일자2 AND a.조작자번호 = :입력조작자번호 AND a.과목코드 IN (‘1’, ’2’) GROUP BY a.거래분류코드; 개선안 SELECT a,거래분류코드, a.sum(전표매수), a.sum(건수), a.sum(금액) FROM 조작자일별상세원장 a, 관서 b WHERE a.국기호 = :입력국기호 AND a.국기호 = b.국기호 AND a.거래일자 BETWEEN :입력거래일자1 AND :입력거래일자2 AND a.조작자번호 = :입력조작자번호 AND a.과목코드 IN (‘1’, ’2’) GROUP BY a.거래분류코드;

5. HAVING WHERE절에 표현할 수 있는 부분을 HAVING절에 표현을 하면 인덱스를 사용할 수 없음 S Q L SELECT a.계정코드, COUNT(*) FROM 일계원장 a WHERE a.국기호 = :입력국기호 GROUP BY a.계정코드 HAVING a.계정코드 > ‘AB100’; 개선안 SELECT a.계정코드, COUNT(*) FROM 일계원장 a WHERE a.국기호 = :입력국기호 AND a.계정코드 > ‘AB100’ GROUP BY a.계정코드 ; Example

6. EXISTS 유무의 체크는 EXISTS 구문 사용 SELECT a.조작자번호, a.국기호 FROM 조작자정보 a Q L SELECT a.조작자번호, a.국기호 FROM 조작자정보 a WHERE a.조작자번호 IN (SELECT b.조작자번호 FROM 조작자일별상세원장 b) ; 개선안 SELECT a.조작자번호, a.국기호 FROM 조작자정보 a WHERE EXISTS (SELECT ‘X’ FROM 조작자일별상세원장 b WHERE b.조작자번호 = a.조작자번호) ;

6. EXISTS(Cont.) and일 경우엔 Where 구문 다음에, or일 경우엔 Where 구문 마지막에 사용 S Q L Select … From dept D, Emp E Where E.deptno = D.deptno And E.emp_type = ‘MANAGER’ And D.dept_cat = ‘A’; Select … From dept D, Emp E Where E.deptno = D.deptno And E.emp_type = ‘MANAGER’ Or D.dept_cat = ‘A’; 개선안 Select … From emp E Where exist ( Select ‘x’ From dept Where deptno = E.deptno And dept_cat = ‘A’) And E.emp_type = ‘MANAGER’; Select … From emp E Where E.emp_type = ‘MANAGER’ Or exist ( Select ‘x’ From dept Where deptno = E.deptno And dept_cat = ‘A’);

6. EXISTS(Cont.) Distinct는 내부 sorting이 일어나 성능의 저하를 가져옴 Q L Select distinct deptno, deptname From dept d, emp e Where d.deptno = e.deptno 개선안 Select deptno, deptname From dept D Where exists (select ‘x’ from emp E where E.deptno = D.deptno);

6. EXISTS(Cont.) Not in 대신에 Not exists를 사용 select … from emp Q L select … from emp where deptno not in (select deptno from dept where dept_cat = ‘A’); 개선안 select … from emp where not exists (select ‘x’ from dept where dept_cat = ‘A’);

7. DRIVING TABLE 두 개 이상의 테이블을 조인하는 경우, 반드시 중심테이블(driving table)이 있어야 함. S Q L Select count(*) From Emp E, Dept D, Location L Where D.deptno = E.deptno And L.locano = E.locano And E.empno Between 10000 and 15000; 개선안 Select count(*) From Emp E, Dept D, Location L Where E.empno Between 10000 and 15000 And D.deptno = E.deptno And L.locano = E.locano;

8. 조건구문의 순서 WHERE절 구문의 순서가 SQL 성능 향상에 영향을 미침 Select E.ename /* 15초 */ From emp E Where E.sal > 50000 And E.emp_type = ‘MANAGER’ And 25 < (Select count(*) from emp where emp_mgr = E.empno); 개선안 Select E.ename /* 1초 */ From emp E Where 25 < (Select count(*) from emp where emp_mgr = E.empno); And E.sal > 50000 And E.emp_type = ‘MANAGER’;

9. ROWID Rowid는 가장 빠른 액세스 방법 조회시 For Update 사용 Select rowid, … Into :emp_rowid … From emp Where emp.emp_no = 56789 For Update; Update emp Set emp.ename = ‘xxxxx’ Where rowid = :emp_rowid;

10. DATABASE ACCESS 가능한 데이터베이스의 액세스를 줄인다. 즉, 가능한 물리적 I/O를 줄여 한번의 SQL로 처리 S Q L Select ename, sal, grade From emp Where empno = 1234;   Where empno = 5678; 개선안 Select a.ename, a.sal, a.grade, b.ename, b.sal, b.grade From emp a, emp b Where a.empno = 1234 and b.empno = 5678;

11. DECODE Count, Sum 연산을 할 때, Decode를 사용하면 성능이 향상됨 S Q L 개선안 Select count(*), sum(sal) From emp Where deptno = 1000 And ename like ‘김%’;   Where deptno = 3000 개선안 Select count(decode(deptno, 1000, ‘x’, null)) dept1000_count, count(decode(deptno, 3000, ‘x’, null)) dept3000_count, sum(decode(deptno, 1000, sal, null)) dept1000_sal, sum(decode(deptno, 3000, sal, null)) dept3000_sal From emp Where ename like ‘김%’;

12. INDEX COLUMN 인덱스 컬럼을 가공하게 되면 인덱스를 사용하지 못 함 S Q L Select account_name, trans_date, amount From Transaction Where substr(account_name,1,7) = ‘CAPITAL’; 개선안 Select account_name, trans_date, amount From Transaction Where account_name like ‘CAPITAL%’;

12. INDEX COLUMN(Cont.) Select account_name, trans_date, amount Q L Select account_name, trans_date, amount From Transaction Where amount != 0; 개선안 Select account_name, trans_date, amount From Transaction Where amount > 0;

12. INDEX COLUMN(Cont.) Select account_name, trans_date, amount Q L Select account_name, trans_date, amount From Transaction Where account_name || account_type = ‘MAXA’; 개선안 Select account_name, trans_date, amount From Transaction Where account_name = ‘MAX’ And account_type = ‘A’;

12. INDEX COLUMN(Cont.) Select account_name, trans_date, amount Q L Select account_name, trans_date, amount From Transaction Where Trunc(trans_date) = Trunc(sysdate); 개선안 Select account_name, trans_date, amount From Transaction Where trans_date Between Trunc(sysdate) and Trunc(sysdate) + .99999;

13. IRRELEVANT TABLE SQL성능을 고려하여 관련 없는 테이블도 하나의 SQL로 처리 Select name from emp Where empno = 1000; Select name from dept Where deptno = 200; Select name from item Where itemtype = ‘RAD’; 개선안 Select E.name, D.name, I.name From Emp E, Dept D, Item I, Dual X Where NVL(‘x’,X.dummy) = NVL(‘x’,E.rowid(+)) And NVL(‘x’, X.dummy) = NVL(‘x’,D.rowid(+)) And NVL(‘x’, X.dummy) = NVL(‘x’,I.rowid(+)) And E.empno(+) = 1000 And D.deptno(+) = 200 And I.itemtype(+) = ‘RAD’;

14. Sub-query Table 수 서브쿼리에서 사용하는 테이블의 수를 줄인다. Select ename From emp Where emp_cat = (select max(category) from emp_categories) And sal_range = (select max(sal_range) from emp_categories) And empdept = 2000; 개선안 Select ename From emp Where (emp_cat, sal_range) = (select max(category), max(sal_range) from emp_categories) And empdept = 2000;

II. 사례별 SQL 사용법 가이드

사례 1 – index 사용 기간을 연별로 나누고 월별로 나눈 조건을 주면 인덱스를 사용할 수 있다. S Q L Select a.yy||a.mm, dept, (sale_qty) From sales_summery a Where a.yy||A.mm Between ‘9410’ and ‘9504’ Group by a.yy||a.mm, dept; 개선안 Select a.yy||a.mm, dept, sum(sale_qty) From sales_summery a Where (a.yy = ‘94’ and a.mm betweem ‘10’ and’12’) or (a.yy =’95’ and a.mm between ‘01’ and ‘04’) Group by a.yy||a.mm, dept;

사례 1 (Cont.) in을 union all로 대체 select nvl(code,’’), nvl(desc,’’) Q L select nvl(code,’’), nvl(desc,’’) from items where code like :b1 and item_type in (‘ca’,’da’) and rownum < 21; 개선안 select nvl(code,’’), nvl(desc,’’) from (select code, desc from items where code like :b1 and item_type = ‘ca’ union all select code, desc from items where code like :b1 and item_type = ‘da’) where rownum < 21;

사례 2 - outer join의 이해 코드 테이블과 참조하는 테이블의 조인 S Q L select x.key, x.fld1, y.key, y.col1, y.col2 from tab1 x, tab2 y where x.key = y.key(+) and x.fld1 > ‘aaa’ and y.col1 = 10; select x.key, x.fld1, y.key, y.col1, y.col2 from tab1 x, tab2 y where x.key = y.key(+) and x.fld1 > ‘aaa’ and (y.col1 = 10 or y.col is null); 개선안 select x.key, x.fld1, y.key, y.col1, y.col2 from tab1 x, tab2 y where x.key = y.key(+) and x.fld1 > ‘aaa’ and y.col1(+) = 10;

사례 2 (Cont.) outer join에서 in의 사용 S Q L select x.key, x.fld1, y.key, y.col1, y.col2 from tab1 x, tab2 y where x.key = y.key(+) and x.fld1 > ‘aaa’ and y.col1(+) in (10,30,50); 개선안 select x.key, x.fld1, y.key, y.col1, y.col2 from tab1 x, (select key, col1, col2 from tab2 where col1 in (10,30,50)) y where x.key = y.key(+) and x.fld1 > ‘aaa’;

사례 3 - 배타적 관계에서 outer join의 활용 계좌정보 테이블은 개인고객 계좌 및 법인고객 계좌로 구성 S Q L create table 계좌정보 (계좌번호 varchar2(10) primary key, …. 고객번호 varchar2(10) not null, 고객종류 varchar2(1) not null constraint check_type check (고객종류 in (‘1’,’2’)); cursor for select … from ..where fetch … if (:고객종류 = ‘1’) select 성명 into :고객명 from 개인고객정보 where 고객번호 = :고객번호; 개선안 select a.계좌번호, a.개설일, b.개인고객명, c.법인고객명 from 계좌정보 a, 개인고객 b, 법인고객 c where a.개설일 like ‘199510%’ and a.고객번호 = b.고객번호(+) and a.고객번호 = c.고객번호(+) order by a.개설일;

사례 4 – 조인하는 테이블의 순서에 따른 차이 조인할 때 where구문의 테이블 순서와 컬럼의 상수값의 위치에 따라 실행계획이 달라질 수 있다. 납품실행계획 a (부서번호#,주문번호#,직원번호#):가장 건수가 많다. 주문 b (주문번호#) 고객 d (고객번호#) 수주진행현황 c (회사번호#,부서번호#,주문번호#,주문일자#,고객번호#)

사례 4 (Cont.) S Q L select distinct a.부서번호, a.주문번호, b.주문일자, b.직원번호, b.고객번호, d.출고중지구분 from 납품실행계획a, 주문b, 고객d, 수주진행현황 c where c.부서번호 = b.부서번호 and c.고객번호 = b.고객번호 and c.직원번호 = b.직원번호 and c.주문번호 = b.주문번호 and c.주문일자 = b.주문일자 and a.부서번호 = b.부서번호 and a.주문번호 = b.주문번호 and a.주문일자 = b.주문일자 and a.완료여부 is null and c.고객번호 = d.고객번호 and c.부서번호 = 3000 and c.회사번호 = 3; 개선안 select /*+ordered */ distinct a.부서번호, a.주문번호, b.주문일자, b.직원번호, b.고객번호, d.출고중지구분 from 수주진행현황 c, 납품실행계획 a, 고객 d, 주문 b (c의 범위를 줄여서 드라이빙 테이블로 이용한다.) where c.부서번호 = b.부서번호 and c.고객번호 = b.고객번호 and c.직원번호 = b.직원번호 and c.주문번호 = b.주문번호 and c.주문일자 = b.주문일자 and a.부서번호 = c.부서번호 and a.주문번호 = c.주문번호 and a.주문일자 = c.주문일자 and a.완료여부 is null and c.고객번호 = d.고객번호 and c.부서번호 = 3000 and c.회사번호 = 3;

사례 5 – MAX값의 처리 가장 효율적인 MAX값 처리를 위해 index된 컬럼을 이용한다. S Q L 개선안 select stock_q from GFLM600 a where io_date = (select max(io_date) from GFLM600 b where b.car_code = :value1 and b.box_code = :value2 and a.car_code = b.car_code and a.box_code = b.box_code); 개선안 select /*+ index_desc(a GFLM600_PK) :car_code + box_code + io_date */ stock_q from GFLM600 a where car_code = :value1 and box_code = :value2 and rownum = 1;

사례 5 (Cont.) max-min에서 sql분리 S Q L 개선안 select (max(eqpmroom) – min(eqpmroom)) + 1 into :nextroom from thiseqpm where eqpmdept = :value1 and eqpmpart = :value2; 개선안 Select /*+ index_desc (thiseqpm thiseqpm_x1) */ Eqmproom into max_room From thiseqpm Where eqpmdept = :value1 And eqpmpart = :value2 And rownum=1; Select /*+ index_asc (thiseqpm thiseqpm_x1) */ Eqmproom into min_room From thiseqpm Where eqpmdept = :value1 And eqpmpart = :value2 And rownum=1;

사례 6 – 인덱스 칼럼 분리에 따른 문제해결 In line view를 이용한 group by의 효과적인 처리 Sale Table : Product_no + Saledate Product Table : Product_no에 인덱스가 있다. S Q L Select product_no, sum(sale_amt*unit_price) From product Where product_no between ‘P2150’ and ‘P2160’ And saledate like ‘1997%’ Group by product_no; 개선안 Select a.product_no, sum(a.sale_amt*unit_price) From product a, (select product_no from product where product_no between ‘P2150’ and ‘P2160’) b where a.product_no = b.product_no and a.saledate like ‘1995%’ group by a.product_no;

사례 6 (Cont.) Decode와 group by의 효율적인 사용 S Q L 개선안 Select job_class, sex, sum(decode(reg_wd,’200101’,1,0))as 0101월, sum(decode(reg_wd,’ 200102’,1,0))as 0102월, sum(decode(reg_wd,’ 200103’,1,0))as 0103월 from qualifier group by job_class, sex; 개선안 Select JC,SX, sum(decode(R_W,’ 200101’,CNT,0)) as 0101월, sum(decode(R_W,’ 200102’,CNT,0)) as 0102월, sum(decode(R_W,’ 200103’,CNT,0)) as 0103월 from (select /*+ full(qualifier) paraller(qualifier,2) */ job_class as JC, sex as SX, reg_wd as R_W, count(*) as CNT from qulifier group by job_class, sex, reg_wd) group by JC, SX