database.sarang.net
UserID
Passwd
Database
DBMS
MySQL
ㆍPostgreSQL
Firebird
Oracle
Informix
Sybase
MS-SQL
DB2
Cache
CUBRID
LDAP
ALTIBASE
Tibero
DB 문서들
스터디
Community
공지사항
자유게시판
구인|구직
DSN 갤러리
도움주신분들
Admin
운영게시판
최근게시물
PostgreSQL Q&A 7074 게시물 읽기
No. 7074
날짜 조건 포함에 따른 속도 저하..
작성자
소심고양이
작성일
2007-03-12 14:13
조회수
5,894

아래는 3개의 테이블을 검색한 결과를 취득하는 경우입니다. 
시작일, 종료일이 있어 오늘의 날과 비교하여 
해당 데이터(시작일 <= 오늘 <= 종료일)만 취득 하게 됩니다. 
그런데 보통 아래의 실행속도가 100ms가 나오는데
주석 처리한 부분을 포함 시키면 1200ms정도가 실행 속도가 저하됩니다. 
다른 테이블에서도 같은 처리를 하고 있는데 왜 이렇게 속도가 저하 되는지..
특별히 인덱스를 주지는 않았습니다. 
이 정도의 차이가 어디서 오는지요?

SELECT
    a.valid_start_date AS valid_start_date_ap_b, a.valid_end_date AS valid_end_date_ap_b,
    c.valid_start_date AS valid_start_date_ap_m, c.valid_end_date AS valid_end_date_ap_m,
    d.valid_start_date AS valid_start_date_ap_s, d.valid_end_date AS valid_end_date_ap_s
   FROM ap_b_vw a, ap_m_vw c, ap_s_vw d
WHERE
    d.ap_b_cd = c.ap_b_cd
    AND d.ap_m_cd = c.ap_m_cd
    AND c.ap_b_cd = a.ap_b_cd
    AND a.mst_kind_cd::text = c.mst_kind_cd::text
    AND a.ap_mst_ver = c.ap_mst_ver
    AND a.mst_kind_cd::text = d.mst_kind_cd::text
    AND a.ap_mst_ver = d.ap_mst_ver

    and (c.valid_start_date IS NULL
    AND c.valid_end_date IS NULL
    OR to_date(c.valid_start_date, 'YYYYMMDD'::text) <= to_date(now(), 'YYYYMMDD'::text)
--    AND c.valid_end_date IS NULL
    OR to_char(c.valid_start_date, 'YYYYMMDD'::text) <= to_char(now(), 'YYYYMMDD'::text)
    AND to_char(c.valid_end_date, 'YYYYMMDD'::text) >= to_char(now(), 'YYYYMMDD'::text)
    OR c.valid_start_date IS NULL
    AND to_char(c.valid_end_date, 'YYYYMMDD'::text) >= to_char(now(), 'YYYYMMDD'::text))

    AND (a.valid_start_date IS NULL
    AND a.valid_end_date IS NULL
    OR to_char(a.valid_start_date, 'YYYYMMDD'::text) <= to_char(now(), 'YYYYMMDD'::text)
    AND a.valid_end_date IS NULL
    OR to_char(a.valid_start_date, 'YYYYMMDD'::text) <= to_char(now(), 'YYYYMMDD'::text)
    AND to_char(a.valid_end_date, 'YYYYMMDD'::text) >= to_char(now(), 'YYYYMMDD'::text)
    OR a.valid_start_date IS NULL
    AND to_char(a.valid_end_date, 'YYYYMMDD'::text) >= to_char(now(), 'YYYYMMDD'::text));

<EXPALIN ANALYZE 결과>
 주석 사용
 "Hash Join  (cost=36.56..54.07 rows=1 width=48) (actual time=16.287..22.896 rows=499 loops=1)"
"  Hash Cond: ((c.ap_b_cd = a.ap_b_cd) AND ((c.mst_kind_cd)::text = (a.mst_kind_cd)::text) AND (c.ap_m_cd = d.ap_m_cd))"
"  Join Filter: (a.ap_mst_ver = c.ap_mst_ver)"
"  ->  Seq Scan on ap_m  (cost=0.00..15.84 rows=78 width=581) (actual time=0.181..3.446 rows=190 loops=1)"
"        Filter: (((valid_start_date IS NULL) AND (valid_end_date IS NULL)) OR (to_date((valid_start_date)::text, 'YYYYMMDD'::text) <= to_date((now())::text, 'YYYYMMDD'::text)) OR ((to_char(valid_start_date, 'YYYYMMDD'::text) <= to_char(now(), 'YYYYMMDD'::text)) AND (to_char(valid_end_date, 'YYYYMMDD'::text) >= to_char(now(), 'YYYYMMDD'::text))) OR ((valid_start_date IS NULL) AND (to_char(valid_end_date, 'YYYYMMDD'::text) >= to_char(now(), 'YYYYMMDD'::text))))"
"  ->  Hash  (cost=36.54..36.54 rows=1 width=116) (actual time=16.051..16.051 rows=499 loops=1)"
"        ->  Hash Join  (cost=7.84..36.54 rows=1 width=116) (actual time=1.317..14.234 rows=499 loops=1)"
"              Hash Cond: (((d.mst_kind_cd)::text = (a.mst_kind_cd)::text) AND (d.ap_b_cd = a.ap_b_cd))"
"              Join Filter: (a.ap_mst_ver = d.ap_mst_ver)"
"              ->  Seq Scan on ap_s  (cost=0.00..20.78 rows=452 width=289) (actual time=0.107..9.118 rows=537 loops=1)"
"              ->  Hash  (cost=7.72..7.72 rows=8 width=53) (actual time=1.175..1.175 rows=46 loops=1)"
"                    ->  Subquery Scan a  (cost=0.00..7.72 rows=8 width=53) (actual time=0.106..1.033 rows=46 loops=1)"
"                          ->  Seq Scan on ap_b  (cost=0.00..7.64 rows=8 width=571) (actual time=0.103..0.940 rows=46 loops=1)"
"                                Filter: (((valid_start_date IS NULL) AND (valid_end_date IS NULL)) OR ((to_char(valid_start_date, 'YYYYMMDD'::text) <= to_char(now(), 'YYYYMMDD'::text)) AND (valid_end_date IS NULL)) OR ((to_char(valid_start_date, 'YYYYMMDD'::text) <= to_char(now(), 'YYYYMMDD'::text)) AND (to_char(valid_end_date, 'YYYYMMDD'::text) >= to_char(now(), 'YYYYMMDD'::text))) OR ((valid_start_date IS NULL) AND (to_char(valid_end_date, 'YYYYMMDD'::text) >= to_char(now(), 'YYYYMMDD'::text))))"
"Total runtime: 23.567 ms"

주석미사용
"Nested Loop  (cost=7.84..52.76 rows=1 width=48) (actual time=1.677..1262.605 rows=499 loops=1)"
"  Join Filter: ((c.ap_b_cd = a.ap_b_cd) AND ((a.mst_kind_cd)::text = (c.mst_kind_cd)::text) AND (a.ap_mst_ver = c.ap_mst_ver) AND (d.ap_m_cd = c.ap_m_cd))"
"  ->  Hash Join  (cost=7.84..36.54 rows=1 width=116) (actual time=1.344..10.918 rows=499 loops=1)"
"        Hash Cond: (((d.mst_kind_cd)::text = (a.mst_kind_cd)::text) AND (d.ap_b_cd = a.ap_b_cd))"
"        Join Filter: (a.ap_mst_ver = d.ap_mst_ver)"
"        ->  Seq Scan on ap_s  (cost=0.00..20.78 rows=452 width=289) (actual time=0.150..6.679 rows=537 loops=1)"
"        ->  Hash  (cost=7.72..7.72 rows=8 width=53) (actual time=1.153..1.153 rows=46 loops=1)"
"              ->  Subquery Scan a  (cost=0.00..7.72 rows=8 width=53) (actual time=0.110..1.011 rows=46 loops=1)"
"                    ->  Seq Scan on ap_b  (cost=0.00..7.64 rows=8 width=571) (actual time=0.107..0.916 rows=46 loops=1)"
"                          Filter: (((valid_start_date IS NULL) AND (valid_end_date IS NULL)) OR ((to_char(valid_start_date, 'YYYYMMDD'::text) <= to_char(now(), 'YYYYMMDD'::text)) AND (valid_end_date IS NULL)) OR ((to_char(valid_start_date, 'YYYYMMDD'::text) <= to_char(now(), 'YYYYMMDD'::text)) AND (to_char(valid_end_date, 'YYYYMMDD'::text) >= to_char(now(), 'YYYYMMDD'::text))) OR ((valid_start_date IS NULL) AND (to_char(valid_end_date, 'YYYYMMDD'::text) >= to_char(now(), 'YYYYMMDD'::text))))"
"  ->  Seq Scan on ap_m  (cost=0.00..15.56 rows=22 width=581) (actual time=0.017..2.251 rows=190 loops=499)"
"        Filter: (((valid_start_date IS NULL) AND (valid_end_date IS NULL)) OR ((to_date((valid_start_date)::text, 'YYYYMMDD'::text) <= to_date((now())::text, 'YYYYMMDD'::text)) AND (valid_end_date IS NULL)) OR ((to_char(valid_start_date, 'YYYYMMDD'::text) <= to_char(now(), 'YYYYMMDD'::text)) AND (to_char(valid_end_date, 'YYYYMMDD'::text) >= to_char(now(), 'YYYYMMDD'::text))) OR ((valid_start_date IS NULL) AND (to_char(valid_end_date, 'YYYYMMDD'::text) >= to_char(now(), 'YYYYMMDD'::text))))"
"Total runtime: 1263.187 ms"

이 글에 대한 댓글이 총 2건 있습니다.

explain 결과 상으로는 그놈이 끼어들면서, 

모든 테이블에 대한 a, c, d 모든 테이블에 대해서 nested loop 가 일어나서 

비용이 많이 드나보네요.

nested loop 는 db 이론상 그 loop 작업을 할 때, 검색 조건 단위로 인덱스를 쓰면 꽤나 빨라지겠지만, 

그렇지 않다면, 정확히 

a row 개수 * c row * d row 개수 

이 만큼 반복작업을 하게 될것입니다. 


왜 nested loop로 검색 할 수 밖에 없는지는 모르겠습니다. 

쿼리가 워낙 예술이라서. ^^


특별히 조언해 드릴 것은 없고, 

먼저,

쿼리 최적화기가 왜 저런 반응을 했는지 보다, 

사람 눈으로 보기 편한 쿼리 최적화가 먼저일듯싶네요. ^^


to_char(c.valid_start_date, 'YYYYMMDD'::text) <= to_char(now(), 'YYYYMMDD'::text)


c.valid_start_date 자료형이 date 형이라면, 


c.valid_start_date <= current_date 


로 변경이 가능할 듯싶습니다.


일단 위에서 처럼 쿼리를 만들 수 밖에 없다면, 

자료설계를 좀더 꼼꼼히 하셔야할 듯싶습니다. :)


자료가 많아지면, 분명 윗 방식의 쿼리는 도저히 쓸 수 없는 쿼리가 되거든요.

김상기(ioseph)님이 2007-03-12 22:13에 작성한 댓글입니다.

답변 감사드립니다.
그런 이유도 있는 거군요. 도저히 알수없는 암호문이 아니었군요. ㅋㅋ
현재 수정을 하고 있는데 자료가 아무것도 없고,
전에 있는 소스만 보고 하는 중이라...왜 저기서 저런 데이터를 뽑는줄도 모르겠고...-_-;
우선 처리 속도만 개선해 달라는데, 디비를 안해본지도 어언...2년이고, Oracle만 잠깐 해본거고..
안습입니다.
더불어 지적해주신 부분은 
c.valid_start_date  < current_date::timestamp 
식으로 수정했습니다. ^^;;

소심고양이님이 2007-03-13 14:57에 작성한 댓글입니다.
이 댓글은 2007-03-13 15:31에 마지막으로 수정되었습니다. Edit
[Top]
No.
제목
작성자
작성일
조회
7077질문있습니다. [4]
조진우
2007-03-16
4273
7076psql 초보입니당 table을 예재를 보고 만들었는데 ... [1]
오승환
2007-03-15
4338
7075두 sql결과가 틀린 이유가 뭔지 혹시 아시나요? [1]
궁금이
2007-03-14
4199
7074날짜 조건 포함에 따른 속도 저하.. [2]
소심고양이
2007-03-12
5894
7073[급함]다시한번 질문 드립니다. [1]
나그네
2007-03-10
4137
7072잔액 계산을 하는 쿼리 질문입니다. [1]
가우나라
2007-03-06
4473
7071쿼리 질문입니다. [1]
조진우
2007-03-06
4575
Valid XHTML 1.0!
All about the DATABASE... Copyleft 1999-2024 DSN, All rights reserved.
작업시간: 0.019초, 이곳 서비스는
	PostgreSQL v16.2로 자료를 관리합니다