오라클 성능 고도화 원리와 해법 II (2012년)
고급 조인 테크닉 - 선분이력 조인 0 0 29,097

by 구루비스터디 고급조인테크닉 선분이력 [2023.10.01]


(8) 선분이력 조인

  • 단일 선분이력을 조회하는 기본 패턴과 인덱스 스캔 효율을 높이는 방안에 대해서는 1장에서 자세히 설명함.
과거/현재/미래의 임의 시점 조회


  • 그림 2-36과 같이 고객등급과 전화번호 변경이력을 관리하는 두 선분이력 테이블이 있다고 하자.
  • 고객과 이 두 선분이력 테이블을 조인해서 2004년 9월 1일 시점 데이터를 조회할 때는 아래와 같이 쿼리하면 된다.
  • 물론 :dt 변수에는 '20040901'(시작일자, 종료일자가 문자열 컬럼일 때)을 입력한다.

select c.고객번호, c.고객명, c1.고객등급, c2.전화번호
from   고객 c, 고객등급변경이력 c1, 전화번호변경이력 c2
where c.고객번호 = 123
and    c1.고객번호 = c.고객번호
and    c2.고객번호 = c.고객번호
and   :dt between c1.시작일자 and c1.종료일자
and   :dt between c2.시작일자 and c2.종료일자


  • 123번 고객의 등급과 전화번호 변경이력 레코드를 수평선상에 펼쳐 시계열적으로 표현했을 때 그림 2-37과 같다면, 위 쿼리 결과로서 고객등급은 'B', 고객전화번호는 '987-6543'으로 조회될 것이다.



현재 시점 조회
  • 위 쿼리를 이용해 과거, 현재, 미래 어느 시점이든 조회할 수 있지만, 만약 미래 시점 데이터를 미리 입력하는 예약 기능이 없다면 "현재 시점(즉, 현재 유효한 시점)" 조회는 아래와 같이 '=' 조건으로 만들어 주는 것이 효과적이다.

select c.고객번호, c.고객명, c1.고객등급, c2.전화번호
from   고객 c, 고객등급변경이력 c1, 전화번호변경이력 c2
where c.고객번호 = 123
and    c1.고객번호 = c.고객번호
and    c2.고객번호 = c.고객번호
and    c1.종료일자 = '99991231'
and    c2.종료일자 = '99991231'



  • 현재가 2005년 6월 7일인데 그림 2-38처럼 미래 시점인 6월 8일 데이터를 미리 입력해두는 기능이 있다면, 현재 시점을 조회할 때 아래와 같이 sysdate와 between을 사용해야만 한다.

select c.고객번호, c.고객명, c1.고객등급, c2.전화번호
from   고객 c, 고객등급변경이력 c1, 전화번호변경이력 c2
where c.고객번호 = 123
and    c1.고객번호 = c.고객번호
and    c2.고객번호 = c.고객번호
and    to_char(sysdate, 'yyyymmdd') between c1.시작일자 and c1.종료일자
and    to_char(sysdate, 'yyyymmdd') between c2.시작일자 and c2.종료일자


Between 조인
  • 지금까지는 선분이력 조건이 상수였다.
  • 즉, 조회 시점이 정해져 있었다.
  • 그림 2-39에서 만약 우측(일별종목거래 및 시세)과 같은 일별 거래 테이블로부터 읽히는 미지의 거래일자 시점으로 선분이력(종목이력)을 조회할 때는 어떻게 해야 할까?
  • 이때는 between 조인을 이용하면 된다.



  • 아래는 주식시장에서 과거 20년 동안 당일 최고가로 장을 마친(종가=최고가) 종목을 조회하는 쿼리다.
  • 그림 2-39의 일별종목거래및시세 테이블로부터 시가, 종가, 거래 데이터를 읽고 그 당시 종목명과 상장주식수는 종목이력으로부터 가져오는데, 조인 연산자가 '=' 이 아니라 between이라는 점이 특징적이다.

select a.거래일자, a.종목코드, b.종목한글명, b.종목영문명, b.상장주식수
        , a.시가, a.종가, a.체결건수, a.체결수량, a.거래대금
from 일별종목거래및시세 a, 종목이력 b
where a.거래일자 between to_char(add_months(sysdate, -20*12), 'yyyymmdd')
								and to_char(sysdate-1, 'yyyymmdd')
and a.종가 = a.최고가
and b.종목코드 = a.종목코드
and a.거래일자 between b.시작일자 and b.종료일자

  • 이런 식으로 조회하면 현재(=최종) 시점의 종목명을 가져오는 것이 아니라 그림 2-40에서 보는 것처럼 거래가 일어난 바로 그 시점의 종목명을 읽게 된다.



  • 거래 시점이 아니라 현재(=최종) 시점의 종목명과 상장주식수를 출력하려면 between 조인 대신 아래와 같이 상수 조건으로 입력해야 한다(그림 2-41 참조).

select a.거래일자, a.종목코드, b.종목한글명, b.종목영문명, b.상장주식수
        , a.시가, a.종가, a.체결건수, a.체결수량, a.거래대금
from 일별종목거래및시세 a, 종목이력 b
where a.거래일자 between to_char(add_months(sysdate, -20*12), 'yyyymmdd')
								and to_char(sysdate-1, 'yyyymmdd')
and a.종가 = a.최고가
and b.종목코드 = a.종목코드
and to_char(sysdate, 'yyyymmdd') between b.시작일자 and b.종료일자


  • 위 쿼리는 종목 테이블을 종목이력과 통합해 하나로 설계했을 때 사용하는 방식이다.
  • 그림 2-39처럼 종목과 종목이력을 따로 설계했을 때는 최종 시점을 위해 종목 테이블과 조인하면 된다.
"구루비 데이터베이스 스터디모임" 에서 2012년에 "오라클 성능 고도화 원리와 해법 II " 도서를 스터디하면서 정리한 내용 입니다.

- 강좌 URL : http://www.gurubee.net/lecture/4438

- 구루비 강좌는 개인의 학습용으로만 사용 할 수 있으며, 다른 웹 페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^

- 구루비 강좌는 서비스 제공을 위한 목적이나, 학원 홍보, 수익을 얻기 위한 용도로 사용 할 수 없습니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입