select *
이므로 없다.
board - article - member 순서로 cardinality 커지기 때문에, 그 순서로 조인하자.
즉 게시글, article 테이블을 딱 850개 정도만 봐야 한다는 뜻이다. 그렇게 하려면 인덱스 스캔을 해야 한다.
board 에서 article로 조인할 때 brd_id로 index range scan을 할텐데, 이때 a.reg_dt 칼럼도 같이 쓰면 article 에서 850개 로우만 보게 될 것이다.
-- 인덱스 변경
ARTICLE_X01: BRD_ID, A.REG_DT
SELECT /*+ ORDERED USE_NL(A M) */ *
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;
출처에서 작성자는 sort 연산을 skip 하기 위해 index_desc(a article_x01)을 추가해준다고 했는데, 경험 상 조인된 테이블에선 그렇게 해도 sort 연산을 생략할 수가 없다.
SELECT 절에선 A, B, C만 쓰고 있다.
MATERIAL 테이블은 필요하지 않다.
STAT_CD NOT IN ('03', '04')라고 했는데, 어차피 03, 04가 아닌 건 01, 02 밖에 없다.
저걸 그대로 놔두면 full scan을 하게 된다.
STAT_CD IN ('01', '02') 로 바꿔준다.
Order 테이블에서 부분범위처리가 많이 일어나기 때문에, order, company, ord_material 순으로 조인한다. order 다음엔 어느 순서로 하든 딱히 상관은 없다.
ORD_MATERIAL 테이블이 1년 단위로 파티션 되어 있고, 해당 쿼리도 최근 1년을 자주 조회한다고 한다. ORDER에서 ORD_MATERIAL로 갈 때 ORD_NO를 사용하는데, ORD_MATERIAL 테이블에 ORD_NO, ORD_DT로 local non prefixed partition index를 생성해주자.
local 인 이유는 ORD_MATERIAL이 연 단위로 나뉘어 있는 이력성 데이터이기 때문이고, non prefixed인 이유는 파티션키는 ord_dt인데 선두는 ord_no이기 때문이다.
파티션 키 칼럼이 범위검색 조건으로 자주 사용된다면 Local prefixed보다 local nonprefixed가 유리하다.
--인덱스 추가
ORD_MATERIAL_X01: ORD_NO, ORD_DT (local nonprefiexed)
SELECT /*+ ordered 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
GROUP BY A.ORD_NO, C.CMP_ID, C.CMP_NM;