intranet query tuning (example)

18
Database query tuning ( 포털 서비스 응답 성능 개선 ) 20160304(곽중선)

Upload: -

Post on 21-Jan-2018

472 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Intranet query tuning (example)

Database query tuning

(포털 서비스 응답 성능 개선)

2016년 03월 04일

(곽중선)

Page 2: Intranet query tuning (example)

Technical document

2 / 18

1. 포털 성능 개선

1.1 작업 개요

모 언론사 사내 인트라넷 서비스의 응답 성능 개선 작업

포털 서비스의 응답 속도가 현저히 저하되어 사용자들의 업무에 지장을 초래하고 있으며, 이에 포털

서비스의 쿼리 성능을 분석하고 튜닝하였음.

1.2 개선 내용

1.2.1 최근 게시 목록

현행 쿼리

SELECT doc_bbsid, doc_subject, doc_yearmon, doc_number, doc_writer

FROM igt_bbs

WHERE doc_urgency='Y' and doc_regdate > dateadd(dd,-1,getdate())

AND resv_date <= getdate() and resv_date > dateadd(dd,-30,getdate())

AND is_restrict not like 'Y' order by doc_seq desc, doc_subseq asc

문제점

order by 절로 인해서 임시 테이블(worktable)이 생성되며, 포털 서비스에 사용자 접속 수가 증가할 경

우 자원의 부족이 발생하고 응답속도가 떨어짐.

조치 사항 및 개선점

SELECT doc_bbsid, doc_subject, doc_yearmon, doc_number, doc_writer

FROM igt_bbs

WHERE doc_urgency='Y' and doc_regdate > dateadd(dd,-1,getdate())

AND resv_date <= getdate() AND is_restrict not like 'Y' order by

doc_regdate desc

order by 절을 개선하여 임시 테이블이 생성되지 않도록 하였고, 쿼리 실행 단계가 2단계에서 1단계

로 단축되었음. 또한, 불필요한 조건을 제거하여 쿼리를 단순화 시킴

1.2.2 공지 확인

현행 쿼리

SELECT ltrim(notice_info) a FROM igt_notice WHERE userlog_id='17140'

Page 3: Intranet query tuning (example)

Technical document

3 / 18

문제점

사용자가 공지 알림을 확인하였는지 확인하는 쿼리. ltrim 함수가 쿼리에 포함되어 있으므로 쿼리 실

행 시 인덱스를 사용하지 못하고, 3천여건에 달하는 레코드를 전부 조회함

조치 사항 및 개선점

SELECT notice_info a FROM igt_notice WHERE userlog_id='17140'

if(ninfo == "") -> if(ninfo.indexOf("Y") == -1 )

쿼리 상에서 함수를 사용하지 않도록 변경하고, 자바 스크립트 소스를 수정함. 인덱스를 사용함으로

쿼리 성능이 개선되었음.

1.2.3 긴급 메일 알람

현행 쿼리

SELECT count(*) as cnt

FROM igt_mail_inbox a, igt_mail b

WHERE a.doc_yearmon = b.doc_yearmon AND a.doc_number =b.doc_number

AND a.receiver= [client_id] AND a.recv_date IS NULL AND a.send_reserve

<= [current_date]

AND b.doc_spec ='긴급'

문제점

사용자의 수신 메일 중 긴급 메일에 한정하여 수신 건수를 출력하도록 개선하였으나, 그룹웨어 테이

블 중에서 데이터 양이 매우 많은 전자우편 테이블 2가지를 조인(join)함으로써 성능 저하 발생.

임시 테이블(worktable)이 생성되지는 않지만, 데이터 건수가 많음으로 인해서 논리적 읽기 횟수가

90 정도로 상당히 높음. (포털의 여타 쿼리들의 평균 논리적 읽기 횟수는 4~5회)

조치 사항 및 개선점

메일 수신 건수를 출력하지 않도록 변경함.

1.3 차주 작업 계획

1.3.1 메일 긴급 개선 알림

임시로 제거한 메일 알람 기능을 복원.

메일 발송 시 긴급 메일인 경우, igt_mail_inbox(메일 수신 알람) 테이블에 기록함으로써 수신 측 포털

페이지에서 쿼리 시 조인(join)을 사용하지 않고 수신 확인토록 변경

Page 4: Intranet query tuning (example)

Technical document

4 / 18

1.3.2 게시판 성능 개선

게시판 전반에 걸쳐 2차 프로젝트 이후 다음과 같은 변동으로 성능 저하 발생

쿼리 복잡도가 증가

페이지 당 출력 레코드 수 증가

게시판 수 증가 (10배 가량)

이에 게시판 전반에 걸쳐 쿼리 수행 시 임시 테이블(worktable)이 발생하고, 출력 성능이 낮아짐.

1.3.3 포털 성능 개선

업무 공지 / 최근 소식 / 부서 공지

SELECT doc_bbsid, doc_subject, doc_writername, doc_yearmon, doc_number,

doc_writer, doc_regdate , writer_deptname

from igt_bbs where doc_bbsid in ( '4200000', '4200000', '4200000e') and

doc_regdate > dateadd(dd,-3,getdate())

and resv_date <= getdate() and resv_date > dateadd(dd,-30,getdate()) and

is_restrict not like 'Y'

order by doc_regdate desc

게시판 쿼리가 복잡하여, 임시 테이블이 발생함. 인덱스 개선 혹은 쿼리 변경 등 검토 필요.

메일 수신 내역

select

a.doc_yearmon,a.doc_number,b.doc_subject,b.doc_writer,b.doc_writername,b

.doc_spec,b.doc_type,a.doc_open, a.folder_date as openedDate,

a.recv_name from igt_mail_docfolder a, igt_mail b

where a.doc_yearmon = b.doc_yearmon and a.doc_number = b.doc_number

and a.userlog_id = '17140' and a.is_display = 'Y'

and a.folder_id = 10 and a.doc_open = 'N'

order by a.send_date desc

메일 수신 내역 쿼리가 복잡하여, 임시 테이블이 발생함. 인덱스 개선 등 검토 필요.

2. 포털 성능 개선 2차

2.1 작업 개요

사내 포털 서비스의 응답 성능 개선 작업

포털 서비스 1차 응답 성능 개선 이후, 포털 게시판 성능개선

Page 5: Intranet query tuning (example)

Technical document

5 / 18

2.2 포털 성능 개선

2.2.1 업무공지 (gwTable1.html)

현행 쿼리

select doc_bbsid, doc_subject, doc_writername, doc_yearmon,

doc_number, writer_deptname,

convert(varchar(10),doc_regdate,111) || ' ' ||

convert(varchar(5),doc_regdate,108) as doc_regdate ,doc_writer

from igt_bbs

where doc_regdate > dateadd(dd,-3,getdate()) and (doc_bbsid='102')

and resv_date <= getdate() and resv_date > dateadd(dd,-30,getdate())

and is_restrict not like 'Y' order by doc_regdate desc

문제점

convert 함수 사용으로 인해, worktable 발생.

조치 사항 및 개선점

select doc_bbsid, doc_subject, doc_writername, doc_yearmon, doc_number,

writer_deptname, doc_regdate ,doc_writer

from igt_bbs (index idx_bbs2)

where doc_regdate > dateadd(dd,-3,getdate()) and (doc_bbsid='102') and

resv_date <= getdate() and resv_date > dateadd(dd,-30,getdate()) and

is_restrict not like 'Y' order by doc_regdate desc

doc_regdate를 convert함수로 변환하지 않고 바로 읽어내면, 자바스크립트의 Date type으로 변환

(conversion) 된다. Date 타입 객체를 문자열로 변환하기 위해 자바스크립트의 date2str() 함수를

/Lib/groupware.js 파일에 추하였고, 결론적으로 worktable이 생성되지 않음. 또한, index hint를 적용하였

음.

아래는 groupware.js 파일에 추가된 date2str 함수 소스이다.

// Date 객체를 문자열로 변환 'YYYY/MM/DD HH24:MI'

function date2str( _date )

{

// 년도 추출

var strYear = _date.getYear();

// 월 추출

var nMonth = _date.getMonth() + 1;

var strMonth = '';

if( nMonth < 10 )

strMonth = '0' + nMonth;

Page 6: Intranet query tuning (example)

Technical document

6 / 18

else

strMonth = '' + nMonth;

// 일자 추출

var nDate = _date.getDate();

var strDate = '';

if( nDate < 10 )

strDate = '0' + nDate;

else

strDate = '' + nDate;

// 시 추출

var nHour = _date.getHours() + 1;

var strHour = '';

if( nHour < 10 )

strHour = '0' + nHour;

else

strHour = '' + nHour;

// 분 추출

var nMin = _date.getMinutes() + 1;

var strMin = '';

if( nMin < 10 )

strMin = '0' + nMin;

else

strMin = '' + nMin;

return strYear + '/' + strMonth + '/' + strDate + ' ' + strHour +

':' + strMin;

}

date2str 사용 예제는 아래와 같다.

cursor = database.cursor(

"select doc_bbsid, doc_subject, doc_writername, doc_yearmon,

doc_number,writer_deptname, doc_regdate, doc_writer from igt_bbs (index

idx_bbs2) where doc_regdate > dateadd(dd,-3,"+now_date()+") and

(doc_bbsid='102') and resv_date <= "+now_date()+" and resv_date >

dateadd(dd,-30,"+now_date()+") and is_restrict not like 'Y' order by

doc_regdate desc" );

// 화면에 최대 5개까지 항목을 보여준다.

for( i=0; cursor.next() && i<5; i++ )

{

record_set1[lc] = cursor.doc_bbsid;

record_set2[lc] = cursor.doc_subject;

record_set3[lc] = cursor.doc_writername;

record_set4[lc] = cursor.doc_yearmon;

record_set5[lc] = cursor.doc_number;

record_set6[lc] = cur_dept.bbs_name;

Page 7: Intranet query tuning (example)

Technical document

7 / 18

record_set7[lc] = cursor.doc_writer;

record_set8[lc] = date2str(cursor.doc_regdate);

record_set9[lc] = cursor.writer_deptname;

}

cursor.close();

2.2.2 본부 공지 (gwTable2.html)

현행 쿼리

SELECT doc_bbsid, doc_subject, doc_writername, doc_yearmon, doc_number,

doc_writer,

convert(varchar(10),doc_regdate,111) || ' ' ||

convert(varchar(5),doc_regdate,108) as doc_regdate , writer_deptname

from igt_bbs where doc_bbsid in ( '4200000', '4200000', '4200000e') and

doc_regdate > dateadd(dd,-3,getdate())

and resv_date <= getdate() and resv_date > dateadd(dd,-30,getdate()) and

is_restrict not like 'Y'

order by doc_regdate desc

문제점

convert 함수 사용 및 doc_bbsid 컬럼에 대한 OR 조건(in 절)으로 인해 worktable 발생.

조치 사항 및 개선점

SELECT doc_bbsid, doc_subject, doc_writername, doc_yearmon, doc_number,

doc_writer, doc_regdate , writer_deptname

from igt_bbs (index idx_bbs2)

where doc_regdate > dateadd(dd,-3,getdate())

and resv_date <= getdate() and resv_date > dateadd(dd,-30,getdate()) and

is_restrict not like 'Y'

order by doc_regdate desc

doc_regdate를 읽어내고, Date 타입 객체를 date2str 함수를 이용해 문자열로 변환함에 따라 worktable

이 생성되지 않음. 인덱스 힌트 사용

2.2.3 최근 게시 (gwTable4.html)

현행 쿼리

select doc_writername, doc_bbsid, doc_yearmon, doc_number, doc_subject,

Page 8: Intranet query tuning (example)

Technical document

8 / 18

doc_writer, convert(varchar(10),doc_regdate,111) || ' ' ||

convert(varchar(5),doc_regdate,108) as doc_regdate, writer_deptname

from igt_bbs

where doc_regdate > dateadd(dd,-3,getdate()) and doc_bbsid in

(select bbs_id from igt_bbs_env where userlog_id='17140')

and resv_date <= getdate() and resv_date > dateadd(dd,-30,getdate())

and is_restrict not like 'Y' order by doc_regdate desc

문제점

convert 함수 사용으로 인해 worktable 발생.

조치 사항 및 개선점

select doc_writername, doc_bbsid, doc_yearmon, doc_number, doc_subject,

doc_writer, doc_regdate

doc_regdate, writer_deptname from igt_bbs (index idx_bbs2)

where doc_regdate > dateadd(dd,-3,getdate()) and doc_bbsid in

(select bbs_id from igt_bbs_env where userlog_id='17140')

and resv_date <= getdate() and resv_date > dateadd(dd,-30,getdate())

and is_restrict not like 'Y' order by doc_regdate desc

doc_regdate를 읽어내고, Date 타입 객체를 date2str 함수를 이용해 문자열로 변환함에 따라 worktable

이 생성되지 않음. 인덱스 힌트 사용

2.2.4 긴급 메일 알람

현행 쿼리

SELECT count(*) as cnt FROM igt_mail_inbox a, igt_mail b

WHERE a.doc_yearmon = b.doc_yearmon AND a.doc_number =b.doc_number

AND a.receiver= [client_id] AND a.recv_date IS NULL AND a.send_reserve

<= [current_date] AND b.doc_spec ='긴급'

문제점

사용자의 수신 메일 중 긴급 메일에 한정하여 수신 건수를 출력하도록 개선하였으나, 그룹웨어 테이

블 중에서 데이터 양이 매우 많은 전자우편 테이블 2가지를 조인(join)함으로써 성능 저하 발생.

임시 테이블(worktable)이 생성되지는 않지만, 데이터 건수가 많음으로 인해서 논리적 읽기 횟수가

90 정도로 상당히 높음. (포털의 여타 쿼리들의 평균 논리적 읽기 횟수는 4~5회)

조치 사항 및 개선점

긴급 알람을 표시하는 컬럼 추가

Page 9: Intranet query tuning (example)

Technical document

9 / 18

alter table igt_mail_inbox add ugent char(1) default 'N'

메일 발송 시 ‘긴급’인 경우는, igt_mail_inbox 테이블의 ugent 컬럼에 ‘Y’ 입력 (mail_DB.html 수정)

포털 화면에서 긴급 메일 여부 확인

SELECT ugent

FROM igt_mail_inbox a, igt_mail b

WHERE a.doc_yearmon = b.doc_yearmon AND a.doc_number =b.doc_number

AND a.receiver= [client_id] AND a.recv_date IS NULL AND a.send_reserve

<= [current_date]

2.3 게시판 성능 개선

2.3.1 게시판 목록 (bbsList.html)

현행 쿼리

select bbs_id, bbs_type, bbs_name, bbs_indent, child_cnt, bbs_content

from igt_bbs_catalog

where bbs_id in ( '4200000', '4200000', '4200000e' ) order by bbs_id

문제점

order by 절로 인해서 임시 테이블(worktable)이 생성된다.

조치 사항 및 개선점

select bbs_id, bbs_type, bbs_name, bbs_indent, child_cnt, bbs_content

from igt_bbs_catalog

where bbs_id in ( '4200000', '4200000', '4200000e' )

order by 절을 생략해도, pk_igt_bbs_catalog 인덱스가 bbs_id 컬럼으로 정렬되어 있으므로 정확한 순서

대로 출력됨.

2.3.2 일반 및 동호회 게시판 목록 (bbsList.html, dept_tree.js)

현행 쿼리

select bbs_id, bbs_type, bbs_name, bbs_indent, child_cnt, bbs_content

Page 10: Intranet query tuning (example)

Technical document

10 / 18

from igt_bbs_catalog

where bbs_type in ('bbs','sign','spec') and bbs_content in ('Y','N')

order by bbs_id

select bbs_id, bbs_type, bbs_name, bbs_indent, child_cnt, bbs_content

from igt_bbs_catalog

where bbs_type='cug' and bbs_id in (select cug_id from igt_user_role

where code_id >= '910' and userlog_id='17140') order by bbs_id

문제점

idx_bbs_catalog(bbs_type) 인덱스를 사용하나, 인덱스 사용으로 인해, worktable 발생.

조치 사항 및 개선점

인덱스를 사용하지 않도록 힌트(hint)를 제공하여, table scan을 유도 (테이블 크기가 작고 변경이 없으

므로, table scan이 유리)

select bbs_id, bbs_type, bbs_name, bbs_indent, child_cnt, bbs_content

from igt_bbs_catalog (index pk_igt_bbs_catalog)

where bbs_type in ('bbs','sign','spec') and bbs_content in ('Y','N')

order by bbs_id

select bbs_id, bbs_type, bbs_name, bbs_indent, child_cnt, bbs_content

from igt_bbs_catalog (index pk_igt_bbs_catalog)

where bbs_type='cug' and bbs_id in (select cug_id from igt_user_role

where code_id >= '910' and userlog_id='17140') order by bbs_id

3. 포털 성능 개선 3차

3.1 작업 개요

포털 로그인 시점에서 예약 메일 수신 확인 기능 적용 후 포털 화면에서 예약 메일 수신 처리(트랜

잭션 발생)로 인해서 포털 서비스 성능 저하.

예약 메일 수신 처리를 백그라운드 데몬 서비스로 분리 개발 및 적용.

3.2 예약 메일 수신 데몬

3.2.1 예약 메일 수신 쿼리

SELECT receiver, doc_yearmon, doc_number from igt_mail_inbox WHERE

recv_date is null and send_reserve <= getdate()

Page 11: Intranet query tuning (example)

Technical document

11 / 18

3.2.2 예약 메일 인덱스 생성

CREATE INDEX idx_mail_inbox2 ON igt_mail_inbox(recv_date, send_reserve)

3.2.3 예약 메일 수신 프로그램

프로그램 위치 : /Groupware/softwares/test90/RecvResv

컴파일 스크립트 : compile.sh

실행 스크립트 : exec.sh

DB 환경 설정 : /Groupware/softwares/test90/RecvResv/jsp/sql/database.properties

3.2.4 작업 개요

- 서버 데몬 실행 스크립트를 실행하면, 30분에 한번씩 RecvResv 자바 어플리케이션 호출

- 예약된 메일 목록을 읽어낸 후, 수신자 메일함에 등록한다.

- 오류 메시지는 화면으로 출력함. (따라서, 로그 저장을 위해서는 redirection 사용해야 함)

4. 성능 개선 4차

4.1 작업 개요

메일 서비스의 느린 응답 시간 개선 및 서버 오류 분석/조치

4.2 메일 응답 성능 개선

index statistics 재성성

전자우편 서비스 쿼리 실행 시 인덱스를 정상적으로 활용하지 못하고 있음. index statistics 재생성하

여 인덱스 사용 효율을 높임. (논리적 읽기 성능 3배 증가)

update all statistics igt_mail_docfolder

메일 서비스의 DB 연결 수 증가

최대 데이터베이스 연결 수를 10에서 40으로 증가. 메일 웹 서버 프로세스가 2개이므로 총 80으로

증가.

메일 문서함 목록 페이지의 쿼리 튜닝

메일 문서함의 문서 건 수를 읽어내는 쿼리는 아래와 같음.

Page 12: Intranet query tuning (example)

Technical document

12 / 18

select count(*) as cnt from igt_mail_docfolder where userlog_id='17140'

and convert(varchar(10),getdate(),111) =

convert(varchar(10),recv_date,111) and is_display='Y' and folder_id in

(1,10) AT isolation 0

isolation level 0 설정된 쿼리에 대한 query plan을 조회한 결과 PK 인덱스를 사용하고 있으며, 응답 성

능이 현저히 낮음.

The type of query is SELECT.

Evaluate Ungrouped COUNT AGGREGATE.

FROM TABLE

igt_mail_docfolder

Nested iteration.

Using Clustered Index.

Index : pk_igt_mail_docfolder

Forward scan.

Positioning at start of table.

Using I/O Size 4 Kbytes for data pages.

With LRU Buffer Replacement Strategy for data pages.

SQL Server cpu time: 600 ms. SQL Server elapsed time: 1833 ms.

isolation 레벨 설정을 제거한 경우 아래와 같이 적절한 인덱스를 사용하며, 응답 시간이 1833ms에서

33ms로 향상되었음.

The type of query is SELECT.

Evaluate Ungrouped COUNT AGGREGATE.

FROM TABLE

igt_mail_docfolder

Nested iteration.

Using 2 Matching Index Scans

Index : idx_mail_docfolder2

Forward scan.

Positioning by key.

Keys are:

userlog_id ASC

folder_id ASC

is_display ASC

Index : idx_mail_docfolder2

Forward scan.

Positioning by key.

Keys are:

userlog_id ASC

Page 13: Intranet query tuning (example)

Technical document

13 / 18

folder_id ASC

is_display ASC

Using I/O Size 4 Kbytes for data pages.

With LRU Buffer Replacement Strategy for data pages.

SQL Server cpu time: 0 ms. SQL Server elapsed time: 33 ms.

4.3 포털 서비스 장애 및 원인 분석

4.3.1 포털 서비스 장애

X월 XX일 오전 중 포털 서비스 일시 중단.

결재 서비스 개선을 위해 결재 웹 서버 프로세스를 중단하였고, 이를 포착한 HA 서비스에서 포털

서비스를 강제 재기동 하였음.

HA 서비스 해제하여 추후 재발하지 않도록 조치

4.3.2 포털 웹 서버 에러 로그 분석

포털 웹 서버 오류 로그 파일에 몇 가지 오류 메시지가 빈번하게 발생함.

no.html 파일을 못 찾는 오류

[08/Jan/2005:22:22:43] warning (5071): for host 10.10.16.31 trying to GET /, send-error reports: error opening

no.html (File not found)

사용자가 루트 페이지 경로를 웹 브라우저에 입력한 경우, 이는 서비스 페이지가 아니므로 위와 같

은 오류가 서버에 남고 사용자 화면에서는 ‘404 not found’ 메시지 표시.

/Groupware/AttVolume/Group 디렉토리에 빈 index.html 파일을 생성하여 위와 같은 오류 제거

cursor 관련 오류

[08/Jan/2005:22:22:43] warning ( 5071): for host 10.10.16.31 trying to GET /, send-error reports: error opening

no.html (File not found)

웹 서버 프로세스가 재기동한 후 웹 서버와 데이터베이스와의 연결이 초기화 되지 못하면 위와 같

은 오류가 빈번히 발생함. 웹 서버 기동 직후 즉시, 데이터베이스 연결이 복구되도록 groupware.js 파

일 수정

// DataBase Conneted..

function dbConnect( force )

{

// force 인자가 ‘true’로 전달되면, db 연결 상태 확인

// 아니면, db_connected 프로젝트 변수 상태를 확인하여,

Page 14: Intranet query tuning (example)

Technical document

14 / 18

// DB 연결 상태이면 return

if( force == null && null2emp(project.db_connected) == 'true' )

return;

// DB와 연결되어 있지 않다면 연결

if( !database.connected() )

{

database.connect("SYBASE","GSVR","gw2user","gw2user","");

}

if( !database.connected() )

{

write("<script>");

write("alert('DATABASE가 DOWN되었습니다.관리자에게 연락하여 주십시

요!');");

write("</script>");

}

// DB 연결에 성공한 경우, db_connected 변수를 true로 설정

else

{

project.db_connected = 'true';

}

}

5. 성능 개선 5차

5.1 작업 개요

포털, 메일 및 게시 서비스 성능 개선.

5.2 포털 쿼리 튜닝

5.2.1 업무 공지 (gwTable1.html)

업무 공지 게시물 목록을 출력하면서, 각각의 게시물이 속한 게시판 이름을 쿼리하고 하는데, 업무

공지에서는 게시판 명칭을 출력하지 않기 때문에 쿼리를 삭제하였음.

5.2.2 최근 메일 (gwTable3.html)

포털 화면에 최근 메일 목록 화면 쿼리 시 화면에는 5건의 메일만을 출력하지만 쿼리 시에 읽어들

이는 레코드 수에 제한이 없으므로 쿼리 실행 시 set rowcount 5 제한을 부여하였음.

Page 15: Intranet query tuning (example)

Technical document

15 / 18

5.3 메일 쿼리 튜닝

5.3.1 보낸 편지함에서 수신여부 쿼리

수신일자 및 회수 가능여부를 확인하는 쿼리가 가장 먼저 수신한 사용자만을 읽어들이기 때문에, 나

머지 레코드를 읽어낼(fetch) 필요가 없다. 따라서, set rowcount 1 제한을 부여하여 읽기 성능 개선.

5.3.2 메일 조회 시 이전 / 이후 문서 연결(link)

메일함의 문서를 조회할 때, 이전 및 이후 문서에 대한 연결을 표시하는 쿼리에 set rowcount 1 제한

을 부여하여 읽기 성능 개선.

5.3.3 메일 수신함의 보낸 사람(부서) 정보 조회

메일 수신함에서 각각의 메일을 보낸 사용자의 성명과 부서를 출력하기 위해서 수신 문서 수만큼의

쿼리가 발생한다.

현행 쿼리

SELECT org_id,userlog_name,userlog_real_name FROM igt_group

WHERE userlog_id = (select userlog_id from igt_member where

group_member='17140')

문제점

inner query를 사용하기 때문에 사실상 2번의 쿼리를 수행한다. 사이베이스에서는 inner query 보다는

join의 성능이 좋다고 판단된다.

조치사항 및 개선점

join 쿼리로 개선한 결과 실행 계획 상으로 2단계 쿼리가 한 단계로 줄어드는 효과 발생

SELECT g.org_id, g.userlog_name, g.userlog_real_name

FROM igt_group g, igt_member m

WHERE g.userlog_id = m.userlog_id AND m.group_member='17140'

5.4 게시 인덱스 튜닝

5.4.1 미열람 게시판 쿼리

가장 나은 성능 개선 효과를 가져왔음.

Page 16: Intranet query tuning (example)

Technical document

16 / 18

현행 쿼리

SELECT count(1) as bNumber FROM igt_bbs WHERE doc_regdate > '2005-01-13'

and is_restrict not like 'Y' and resv_date <= getdate() and

doc_bbsid in

('001','002','102','201','202','203','204','205','206','207',

'208','209','301','302','303','304','401','402','403','404','501','502',

'503','504','601','602','603','604','620','621','701','702',

'703','704','705','99999','4200000', '4200000e' )

문제점

idx_bbs3(doc_bbsid, resv_date, doc_regdate) 인덱스를 사용하며, doc_bbsid 수만큼 인덱스를 반복하여 읽

어들인다. 현재 운영 중인 최근 게시판 수가 38개에 달하기 때문에 상당한 부하를 유발한다.

또한 이러한 쿼리가 미열람 게시판에서 5회에 걸쳐 수행된다.

(오늘 등록 게시물 열람 건수, 오늘 미열람 게시 건수, 최근 게시물 전체 건수, 사용자가 조회한 최

근 게시물 건 수, 게시물 목록 쿼리 등)

조치사항 및 개선점

idx_bbs2(doc_regdate, doc_urgency)를 사용하도록 힌트를 제공하여, 인덱스 스캔 횟수를 한번으로 감소

시킨다. 또한 최근 3일간의 게시물을 조회하기 때문에 인덱스 내부에서도 30~50개의 레코드만을 스

캔하게 됨으로써 효율이 극대화 된다.

산술적으로 38 * 5 (190)회에 걸친 인덱스 조회가 5회로 줄어든다. 또한 인덱스 조회 범위가 전체에서

1%이내로 감소함으로 잠정 효과는 약 50배 이상에 달한다.

SELECT count(1) as bNumber FROM igt_bbs (index idx_bbs2) WHERE

doc_regdate > '2005-01-13'

and is_restrict not like 'Y' and resv_date <= getdate() and

doc_bbsid in

('001','002','102','201','202','203','204','205','206','207',

'208','209','301','302','303','304','401','402','403','404','501','502',

'503','504','601','602','603','604','620','621','701','702',

'703','704','705','99999','4200000', '4200000e' )

6. 성능 개선 6차

6.1 작업 개요

포털, 메일 및 게시 서비스 성능 개선.

Page 17: Intranet query tuning (example)

Technical document

17 / 18

6.2 메일 및 게시 페이지 당 출력 레코드 제한

메일, 게시판 목록의 페이지 당 출력 레코드 수를 50에서 20으로 감소

6.3 포털 쿼리 튜닝

6.3.1 최근 게시 (gwTable4.html)

최근게시 목록 추출 후 개별 게시물을 조회 했는지 여부를 확인하는 쿼리와 게시판 명칭을 추출하

는 쿼리를 실행하던 방식을 개선하여, 3종의 쿼리를 단일 쿼리로 통합하고, set rowcount 5 지정

set rowcount 5

select doc_writername, doc_bbsid, doc_yearmon, doc_number,

doc_subject, doc_writer, doc_regdate, writer_deptname, bbs_name

from igt_bbs (index idx_bbs2), igt_bbs_catalog

where doc_regdate > dateadd(dd,-3,getdate()) and doc_bbsid in

(select bbs_id from igt_bbs_env where userlog_id='17140')

and resv_date <= getdate() and is_restrict not like 'Y'

and doc_number not in (select doc_number from igt_bbs_read where

userlog_id='17140') and bbs_id = doc_bbsid

order by doc_regdate desc

6.3.2 업무공지 (gwTable1.html)

최근 업무공지 목록 추출 후 개별 게시물을 조회 했는지 여부를 확인하는 쿼리를 실행하던 방식을

개선하여, 2종의 쿼리를 단일 쿼리로 통합하고, set rowcount 5 지정

set rowcount 5

select doc_subject, doc_writername, doc_yearmon, doc_number,

writer_deptname, doc_regdate, doc_writer

from igt_bbs (index idx_bbs2)

where doc_regdate > dateadd(dd,-3,getdate()) and doc_bbsid = '102'

and resv_date <= getdate() and is_restrict not like 'Y'

and doc_number not in (select doc_number from igt_bbs_read where

userlog_id='17140')

order by doc_regdate desc

6.3.3 본부 공지 (gwTable2.html) 및 게시속보(gwMain_down.html)

위와 동일한 방식으로 튜닝

SELECT doc_bbsid, doc_subject, doc_writername, doc_yearmon, doc_number,

doc_writer, doc_regdate, writer_deptname from igt_bbs (index idx_bbs2)

Page 18: Intranet query tuning (example)

Technical document

18 / 18

where doc_bbsid in ( '4200000', '4200000', '4200000e') and

doc_regdate > dateadd(dd,-3,getdate()) and resv_date <= getdate()

and is_restrict not like 'Y' and doc_number not in (select doc_number

from igt_bbs_read where userlog_id='17140')

order by doc_regdate desc

select doc_bbsid, doc_subject, doc_yearmon, doc_number, doc_writer from

igt_bbs (index idx_bbs2) where doc_urgency='Y' and doc_regdate >

dateadd(dd,-1,getdate()) and resv_date <= getdate() and is_restrict not

like 'Y' and doc_number not in (select doc_number from igt_bbs_read

where userlog_id='17140') order by doc_regdate desc