[SQLP] SQLP 44회 실기 풀이

jy yoon·2022년 4월 8일
1

자격증

목록 보기
2/2
post-custom-banner

SQLP 실기 기출문제 풀이(44회)

※ 시험후기들을 참고해 복기한것으로 틀린부분이 있을 수 있음.
※ 실제 시험에는 ERD와 ROW SOURCE GENERATION 정보가 같이 나왔음.

1번

(실기1) 아래와 같이 테이블구조가 있는데 기존SQL를 개선하고, 필요시 인덱스를 설계변경 할 것
불필요하게 인덱스 변경시 감점

[테이블 정보]
* BOARD : #BRD_ID, BRD_NM, ...
* ARTICLE : #ART_SN, ART_TIL, ART_CONT, MBR_NO, BRD_ID, REG_DT,  ...
* MEMBER : #MBR_NO, MBR_NM, ...

[인덱스]
BOARD_PK : BRD_ID
ARTICLE_PK : ART_SN
MEMBER_PK : MBR_NO
ARTICLE_X01 : BRD_ID
ARTICLE_X02 : MBR_NO

[정보]
BOARD 테이블 : 10건
최근 3일 또는 5일전 게시글 : 850여 건
MEMBER 테이블 : 5000건(?)

[기존SQL]
SELECT
*
FROM
(SELECT
B.BRD_ID
, B.BRD_NM
, A.ART_SN
, A.ART_TIL
, GET_TEXT(A.ART_CONT,100) AS ART_CONT
, A.MBR_NO
, M.MBR_NM
, A.REG_DT
FROM BOARD B, ARTICLE A, MEMBER M
WHERE B.BRD_ID = :BRD_ID
AND A.BRD_ID = B.BRD_ID
AND A.MBR_NO = M.MBR_NO
AND A.REG_DT >= TRUNC(SYSDATE,-3)
ORDER BY A.REG_DT DESC
)
WHERE ROWNUM <= 5;

제출답안

· 인덱스 재구성 : ARTICLE_X01 : BRD_ID, REG_DTM

SELECT *
FROM (SELECT /*+ LEADING(B A M) USE_NL(A M) INDEX_DESC(A ARTICLE_X01) */B.BRD_ID, B.BRD_NM, A.ART_SN, A.ART_TIL, GET_TEXT(A.ART_CONT,100) AS ART_CONT, A.MBR_NO, M.MBR_NM,A.REG_DT
		FROM BOARD B, ARTICLE A, MEMBER M
	   WHERE B.BRD_ID = :BRD_ID
		AND A.BRD_ID = B.BRD_ID
		AND A.MBR_NO = M.MBR_NO
		AND A.REG_DT >=TRUNC(SYSDATE,-3)
	ORDER BY A.REG_DT DESC
)
WHERE ROWNUM<=5;

해설(내생각)

  • 문제점
    기존 ARTICLE_X01(BRD_ID) 구성으로는 BRD_ID(게시판번호)에 들어있는 게시글을 전부 읽고 5ROW를 뽑는다.
  • 튜닝포인트
    1) ORDER BY 하나의 테이블에 한 컬럼으로 정렬하는 간단한 구성으로, 인덱스 생성해 충분히 sort order by를 제거 할 수 있다.
    2) B.BRD_ID 가 PK이기때문에 B->A 순서로 접근해도 SORT ORDER BY 가 생략된다.
    (A 먼저보면 불필요하게 B를 5번 스캔함.)
  • 추가 개선 여지
    1) CLOB형 컬럼이 있는데 개선포인트?
    딱히 찾지못했음. 어차피 5ROW 읽어야되고 sort order by 제거하면 크게 문제되지 않을것으로 생각됨.
    2) SELECT-LIST에 참여하지 않거나 ERD상으로 불필요 테이블이 있는지?
    불필요 테이블이 있는지 확인했는데 모두 필요한 테이블들.
    3) 조건 추가 할만한게 있는지?
    A 먼저 봐야됐다면 A.BRD_ID = :BRD_ID를 추가해야겠지만, B.BRD_ID가 PK이기에 불필요.


2번

(실기2) 아래와 같이 테이블 구조가 있는데, 기존SQL를 개선하고, 필요시 인덱스를 생성할 것
(생성시 인덱스 및 파티셔닝이 필요하면 local partition 또는 global partition 등 작성, PK는 변경할 수 없음)

[테이블 정보]
* COMPANY : #CMP_ID, CMP_NM, ...
* ORDER : #ORD_NO, ORD_DT, CMP_ID, STAT_CD
* ORD_MATERIAL : #ORD_NO, #MTR_ID, ORD_DT, NUM_QTY, AMT_QTY, DC_QTY
* MATERIAL : #MTR_ID, MTR_NM, ...

[인덱스]
COMPANY_PK : CMP_ID
ORDER_PK : ORD_NO
ORDER_X01 : STAT_CD, ORD_DT
ORD_MATERIAL_PK : ORD_NO, MTR_ID
MATERIAL_PK : MTR_ID

[정보]
ORDER : 약 150여 만건 → STAT_CD 01(5%), 02(5%), 03(40%), 04(50%) 이외의 값은 존재하지 않음
ORD_MATERIAL : 연간 1500여 만건 / ORD_DT가 ORDER 테이블을 반정규화 하여 사용하고 있음 / 연단위로 ORD_DT로 파티셔닝 되어 있음
COMPANY : 5천건
MATERIAL : 1만건
주로 최근 1년을 자주 조회함

[기존SQL]
SELECT
A.ORD_NO
, C.CMP_ID
, C.CMP_NM
, SUM(B.NUM_QTY) AS NUM_QTY
, SUM(B.AMT_QTY) AS AMT_QTY
, SUM(B.DC_QTY) AS DC_QTY
FROM ORDER A, ORD_MATERIAL B, COMPANY C, MATERIAL D
WHERE
A.STAT_CD NOT IN ('03','04')
AND A.ORD_DT BETWEEN TO_DATE(:START_DT,'YYYY-MM-DD') AND TO_DATE(:END_DT,'YYYY-MM-DD')
AND A.ORD_NO = B.ORD_NO
AND A.CMP_ID = C.CMP_ID
AND A.MTR_ID = D.MTR_ID
GROUP BY A.ORD_NO, C.CMP_ID, C.CMP_NM;

제출답안

· 신규 인덱스 생성 : ORD_MATERIAL_X01 : ORD_NO, ORD_DT (LOCAL NON-PREFIXED)

SELECT /*+ LEADING(A B C) USE_NL(B C) INDEX(B ORD_MATERIAL_X01) INDEX(A ORDER_X01) */ A.ORD_NO, C.CMP_ID, C.CMP_NM, SUM(B.NUM_QTY) AS NUM_QTY, SUM(B.AMT_QTY) AS AMT_QTY, SUM(B.DC_QTY) AS DC_QTY
FROM ORDER A, ORD_MATERIAL B, COMPANY C
WHERE A.STAT_CD IN ('01','02')
AND A.ORD_DT BETWEEN TO_DATE(:START_DT,'YYYY-MM-DD') AND TO_DATE(:END_DT,'YYYY-MM-DD')
AND A.ORD_NO = B.ORD_NO
AND A.CMP_ID = C.CMP_ID
AND A.ORD_DT = B.ORD_DT
GROUP BY A.ORD_NO, C.CMP_ID, C.CMP_NM;

해설(내생각)

  • 문제점
    1) STAT_CD 에 '01', '02' 는 전체 중 10% 뿐이나 NOT IN 으로 인해 풀스캔중임.
    -> 너무 IN으로 바꾸고 싶음.
    2) NL JOIN(ORD_NO + ORD_DT) VS HASH JOIN(ORD_DT)
    STAT_CD 10% 라는 부분과 최근 1년 조회가 많다는 걸 보고 전자를 택함
    IF) ORD_DT를 선두로한다면 다른 모든 주문을 불필요하게 읽어야함.

  • 튜닝포인트
    1) STAT_CD NOT_IN을 IN으로 변경해 INDEX SCAN 유도
    ORD_NO이 150만건 테이블이고 최대기간 검색 시 10%인 15만건 정도면 INDEX 스캔해도 괜찮아보임.
    2) ORD_MATERIAL 테이블 인덱스 신규생성 및 A.ORD_DT = B.ORD_DT 조건추가
    ORD_NO + ORD_DT LOCAL로 구성하면 ORD_NO으로 접근 후 파티션 PRNUING가능
    자주 들어오는 연단위조건이 들어올 시 한개의 파티션만 보면됨.
    3) 불필요 테이블 제거하기 : MATERIAL 조인 제거
    SELECT-LIST에 참조하지도 않고, ERD상 ORD_MATERIAL은 반드시 하나의 MATERIAL을 포함하기 때문에 제거가능(EXISTS도 불필요.)

  • 추가 개선여지
    1) A,B 조인 후 GROUP BY 하고나서 COMPANY C와 조인

profile
postgreSQL Mysql MariaDB
post-custom-banner

0개의 댓글