OUTER JOIN OR 조건 튜닝
쿼리 검수를 하는데 처음 접하는 쿼리를 보게 되어 당황스러웠던 경험이 있습니다.
바로 LEFT OUTER JOIN 의 JOIN 절에 OR 조건이 달려있는 쿼리였는데요.
항상 JOIN on a.id = b.id 같은 단일조건, 조건이 더 달려 봤자 AND 조건이었는데 OR 조건은 처음 접하는 경험이었는데요
저는 LEFT OUTER JOIN 절에 OR 조건이 포함되면 인덱스를 타지못해 성능이 좋지 않아 아래와 같이 쿼리를 튜닝했습니다.
쿼리 확인
select
tb1.`ymdt` as col_0_0_,
tb1.`amount` as col_1_0_,
.
.
.
tb4.`c_id` as col_10_0_,
tb4.`issue_id` as col_11_0_
from
tb_test1 tb1
inner join tb_test2 tb2 on tb1.`order_no` = tb2.`order_no`
inner join `tb_test3` tb3 on tb1.`order_no` = tb3.`order_no`
left outer join tb_test4 tb4 on (
tb4.`no` = tb1.`no`
or tb4.`no` = tb1.`origin_no` )
where
tb1.`ymdt` >= ?
and tb1.`ymdt` < ?
and exists (
select '1' from tb_test5 tb5 where tb5.`order_no` = tb1.`order_no`
and ( tb5.`coupon_id` in ( ? )) )
order by
.
.
실행계획
+----+-------------+-----------+------------+------+----------------------------------+---------------+---------+------------------------------+---------+----------+--------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+------+----------------------------------+---------------+---------+------------------------------+---------+----------+--------------------------------------------------+
| 1 | SIMPLE | tb5 | p202002,....| ref | ink1,ink4 | ink4 | 82 | const | 1 | 100.00 | Using temporary; Using filesort; Start temporary |
| 1 | SIMPLE | tb1 | p202010 | ref | ink01, ink03,idx2 | ink03 | 82 | tb5.no | 1 | 23.93 | Using index condition; End temporary |
| 1 | SIMPLE | tb2 | p202002,....| ref | PRIMARY,idx1 | PRIMARY | 82 | tb5.no | 1 | 100.00 | NULL |
| 1 | SIMPLE | tb3 | p202002,....| ref | PRIMARY | PRIMARY | 82 | tb5.order_no | 1 | 100.00 | NULL |
| 1 | SIMPLE | tb4 | p202002,....| ALL | PRIMARY | NULL | NULL | NULL | 4605120 | 100.00 | Range checked for each record (index map: 0x1) |
+----+-------------+-----------+------------+------+----------------------------------+---------------+---------+------------------------------+---------+----------+--------------------------------------------------+
=> 실행 계획이 잘나가다가 tb4 부분을 보면 tb4 를 조인할 때 풀스캔을 하면서 수많은 row를 읽게 됩니다.
LEFT OUTER JOIN 절에 OR 로 인해서 인덱스를 타지 못해서 엄청난 비효율이 발생하고 있습니다.
쿼리 튜닝
select
tb1.`ymdt` as col_0_0_,
tb1.`amount` as col_1_0_,
.
.
.
COALESCE(tb4.`c_id`, tb6.`c_id`) as col_10_0_,
COALESCE(tb4.`issue_id`, tb6.`issue_id`) as col_11_0_
from
tb_test1 tb1
inner join tb_test2 tb2 on tb1.`order_no` = tb2.`order_no`
inner join `tb_test3` tb3 on tb1.`order_no` = tb3.`order_no`
left outer join tb_test4 tb4 on ( tb4.`no` = tb1.`no` )
left outer join tb_test4 tb6 on ( tb6.`no` = tb1.`origin_no`)
where
tb1.`ymdt` >= ?
and tb1.`ymdt` < ?
and exists (
select '1' from tb_test5 tb5 where tb5.`order_no` = tb1.`order_no`
and ( tb5.`coupon_id` in ( ? )) )
order by
.
.
- LEFT OUTER JOIN OR 부분을 컬럼 별로 JOIN 할 수 있도록 수정
- SELECT 절에서 기존 tb4 에서 가져오던 컬럼이 tb4, tb6 으로 나뉘어졌기 때문에 COALESCE 함수를 사용하도록 수정함
튜닝한 쿼리 실행계획
+----+-------------+------------+----------------+-------+-----------------------------+---------------+---------+-------+----------+------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | rows | filtered | Extra |
+----+-------------+------------+----------------+-------+-----------------------------+---------------+---------+-------+----------+------------------------------+
| 1 | SIMPLE | tb1 | p202010 | range | ink01,ink03 | ink01 | 5 | 26702 | 100.00 | Using index condition |
| 1 | SIMPLE | tb4 | p202002,,.... | ref | PRIMARY | PRIMARY | 82 | 1 | 100.00 | NULL |
| 1 | SIMPLE | tb6 | p202002,,.... | ref | PRIMARY | PRIMARY | 82 | 1 | 100.00 | Using index |
| 1 | SIMPLE | tb5 | p202002,,.... | ref | ink1,ink4 | ink1 | 82 | 1 | 30.00 | Using where; Start temporary |
| 1 | SIMPLE | tb2 | p202002,,.... | ref | PRIMARY | PRIMARY | 82 | 1 | 100.00 | NULL |
| 1 | SIMPLE | tb3 | p202002,,.... | ref | PRIMARY | PRIMARY | 82 | 1 | 100.00 | End temporary |
+----+-------------+------------+----------------+-------+-----------------------------+---------------+---------+-------+----------+------------------------------+