where 조건절에 OR 연산을 사용한다면 반영 전에 실행계획을 반드시 확인해야한다.
보통은 거의 쓰지 않거나 최소한으로 쓰는 것이 좋고 대용량테이블을 건드린다면 성능이슈가 발생할 가능성이 크다.
이럴경우 해결할 수 있는 방법은 오라클은 힌트가 있고 mysql은 이전에는 union all로 쪼개서 병합하는 방식을 썼는데
mysql 5.1 이후부터(maridb는 5.0부터던가?..) 인덱스중에 느린 편이지만 index_merge라는 것을 쓸 수 있다.
옵티마이져가 equal 연산(=AND)이 아니더라도 인덱스끼리 분리 추출해서 병합해서 return 해주는 방식인데 인덱스 성능중에 느린 축이라서 무시했는데..
-->이번에 대용량쿼리 튜닝하면서 MariaDB 10.3.8 의 index_merge 성능에 놀라 따로 정리하기로 한다.
1. index_merge 지원여부확인
- mysql or mariadb 버전에서 인덱스병합을 지원하는지 확인해본다.
[maria@localhost ~]$ mysql -uroot -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 13
Server version: 10.3.8-MariaDB-log MariaDB Server
MariaDB [(none)]> select @@optimizer_switch\G;
*************************** 1. row ***************************
@@optimizer_switch: index_merge=on // 지원확인 O
,index_merge_union=on
,index_merge_sort_union=on
,index_merge_intersection=on
,index_merge_sort_intersection=off
,engine_condition_pushdown=off
,index_condition_pushdown=on
,derived_merge=on
,derived_with_keys=on
,firstmatch=on
,loosescan=on
,materialization=on
,in_to_exists=on
,semijoin=on
,partial_match_rowid_merge=on
,partial_match_table_scan=on
,subquery_cache=on
,mrr=off
,mrr_cost_based=off
,mrr_sort_keys=off
,outer_join_with_cache=on
,semijoin_with_cache=on
,join_cache_incremental=on
,join_cache_hashed=on
,join_cache_bka=on
,optimize_join_buffer_size=off
,table_elimination=on
,extended_keys=on
,exists_to_in=on
,orderby_uses_equalities=on
,condition_pushdown_for_derived=on
,split_materialized=on
2. index_merge란?
보통 인덱스 접근방법 = 타입(type) 은 하나의 인덱스만 사용한다.
이와 달리 index_merge 는 2개 이상의 인덱스를 이용해 각각의 검색결과를 만들어낸 후 그 결과를 병합하는 처리방식이다. 하지만 여러 번의 경험을 보면 이름만큼 그렇게 효율적으로 작동하는 것 같지는 않았다. index_merge 접근방식에는 다음과 같은 특징이 있다.
1) 여러 인덱스를 읽어야 하므로 일반적으로 range 접근방식보다 효율성이 떨어진다.
2) AND와 OR 연상이 복잡하게 연결된 쿼리에서는 제대로 최적화되지 못할 때가 많다. -> 데이터 분포도에 따라 옵티마이져가판단함
3) 전문 검색 인덱스(fulltext)를 사용하는 쿼리에서는 index_merge가 적용되지 않는다.
4) index_merge 접근방식으로 처리된 결과는 항상 2개 이상의 집합이 되기 때문에 그 두 집합의 교집합이나 합집합 또는 중복 제거와 같은 부가적인 작업이 더 필요하다.
#실행계획 인덱스 타입 빠른 순서
system > const > eq_ref > ref > fulltext > ref_or_null > unique_subquery > index_subquery > range > index_merge > index > ALL
->all 빼놓곤 다 인덱스스캔이고 뒤로 갈수록 성능이 떨어진다.
#실행계획 extra 부분
1.Using intersect(...)
각각의 인덱스를 사용할 수 있는 조건이 AND로 연결된 경우 각 처리 결과에서 교집합을 추출해내는 작업을 수행했다는 의미이다.
2.Using union(...)
각 인덱스를 사용할 수 있는 조건이 OR로 연결된 경우 각 처리 결과에서 합집합을 추출해내는 작업을 수행했다는 의미다.
3.Using sort_union(...)
Using union과 같은 작업을 수행하지만 Using union으로 처리될 수 없는 경우(OR로 연결된 상대적으로 대량의 range 조건들)이 방식으로 처리된다. Using sort_union 과 Using_union의 차이점은
Using sort_union은 PK만 먼저 읽어서 정렬하고 병합한 후에야 비로소 레코드를 읽어서 반환할 수 있다는 것이다.
Using union()과 Using sort_union()은 둘다 충분히 인덱스를 사용할 수 있는 조건이 OR로 연결된 경우에 사용된다.
Using union()은 대체로 동등 비교(Equal)처럼 일치하는 레코드 건수가 많지 않을 때 사용되고, 각 조건이 크다 또는 작다와 같이 상대적으로 많은 레코드에 일치하는 조건이 사용되는 경우
Using sort_union()이 사용된다. 하지만 실제로는 레코드 건수에 거의 관계없이 각 WHERE 조건에 사용된 비교조건이 모두 동등조건이면 Using union()이 사용되며, 그렇지 않으면 Using_sort_union()이 사용된다.
#알고리즘 참고
Mysql 내부적으로 이 둘의 차이는 정렬 알고리즘에서 싱클 패스 정렬 알고리즘과 투 패스 정렬 알고리즘의 차이와 같다. Using union()이 싱글패스 정렬 알고리즘을 사용한다면,
Using sort_union()은 투패스 정렬 알고리즘을 사용한다. (Real Mysql 334P)
3. 성능튜닝사례
1) where 조건절 확인
WHERE B.SEQ = '16'
AND A.xxx_YN != 'Y'
AND ( C.xx_KEY = '40' OR ( C.xxx_KEY = '518' AND C.xxx_CD != '01' ) )
AND ( ( A.xx_CD IN ( '1', '3' ) AND C.xxxx_CD NOT IN ( '88' ) AND C.xxx_KEY = '401' )
OR ( A.xxx_CD = '2' AND C.xxxx_CD IN ( '01', '09' ) AND C.xxx_KEY = '1518' )
OR ( CI.xxx_KEY = '48' AND A.xxxx_CD NOT IN ( '9' ) ) )
--> 다른팀에서 성능튜닝을 문의해서 확인해보니 굳이 실행계획 안봐도 성능안나오게 생겼다.
복잡한 or연산을 분리해서 테이블 rows건수 보고 union all로 풀려다가 데이터 분포도가 좋은 컬럼이 인덱스가 안되어있어 추가하고
or연산의 index_merge 성능을 한번 확인해보기로 했다.
2) 인덱스 추가후 실행계획 확인
풀스캔이 사라지면서 rows수는 50만건에서 2000여건으로 많이 줄였고, 수행시간은 3초에서 0.05초로 줄었다.
-> 와우 index_merge가 이렇게 빨랐었나?ㅎ
3. 결론
최고의 튜닝은 버전업! 단 버그만 없다면 (MariaDB 10.2 쓰는거 다 10.3이상으로 올려야겠다...;)
데이터 분포도가 좋은 컬럼은 or연산에서 느린 index_merge라도 엄첨 빠르다.
끝~
참조 : Real Mysql
'RDB > mariadb' 카테고리의 다른 글
xtrabackup과 Mariabackup 차이점 (0) | 2020.10.30 |
---|---|
MariaDB 10.4.13 mysql계정으로 stop 안되는 현상 해결 (0) | 2020.10.22 |
xtrabackup 백업 & 압축관련 검토(pigz) (0) | 2020.04.17 |
xtrabackup 장애사례 (0) | 2019.11.26 |
mariadb 10.2.x 이 프로세스 뭐냐? (0) | 2019.10.17 |