MySQL 튜닝 질문 드립니다..
쿼리 내용은 아래와 같습니다.
SELECT 1 FROM A_TABLE A WHERE 1=1 AND (A.SITE_NO , DATE_FORMAT(A.ACCESS_DTTM, '%Y%m%d') , CASE WHEN A.DEVICE_TYPE = 'P' THEN '11' WHEN A.DEVICE_TYPE = 'M' THEN '12' ELSE '99' END , A.IP) NOT IN (SELECT F.SITE_NO, CONCAT(F.YR, F.MM, F.DT), F.EQPM_GB_CD, F.VISIT_IP FROM F_TABLE F WHERE 1=1 AND F.SITE_NO = A.SITE_NO AND F.YR = DATE_FORMAT(A.ACCESS_DTTM, '%Y') AND F.MM = DATE_FORMAT(A.ACCESS_DTTM, '%m') AND F.DT = DATE_FORMAT(A.ACCESS_DTTM, '%d') AND F.EQPM_GB_CD = CASE WHEN A.DEVICE_TYPE = 'P' THEN '11' WHEN A.DEVICE_TYPE = 'M' THEN '12' ELSE '99' END AND F.VISIT_IP = A.IP );
실행계획은 아래와 같습니다.
ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
1 | PRIMARY | A | ALL | 2620137 | Using Where | ||||
2 | DEPENDENT SUBQUERY | F | eq_ref | PRIMARY | PRIMARY | 348 | A.SITE_NO,func,func | 1 | Using Where; Using index |
not in이 옵티마이저에 의해서 not exists로 로 변환되서 수행되는 것 같은데
subquery를 접근할때 1건만 찾고 나와서 문제가 안되는데 A테이블에서 2백만건을 읽어서 그걸 건건히 subquery에 접근하다 보니 문제가 되는것 같습니다.
not in이여서 옵티마이저가 semi로 변환도 안되는 것 같고 join조건만 있고 where절은 없으니 여기서 더 줄일수 있는지도 모르겠습니다.
인터넷에 outer join으로 변형시켜 보라해서 쿼리를 변형시키니 성능이 더 안좋아지는 결과만 나오네요..
현재 수행시간은 30초정도 됩니다. 1시간마다 도는 batch쿼리여서 시간문제는 안되는데 cpu가 100%를 쳐서 이걸 좀 줄여보려고합니다.
nl조인은 cpu가 많이 안드는걸로 아는데 이것도 좀 이상하네요....
계속 고민하다가 고수님들께 질문드려봅니다. oracle과 달라서 많이 헷갈리네요.
1. 넵. 그부분은 이상하게 생각하여서 SUBQUERY에 있는 WHERE절을 제외시켜서 동작시키니 성능상 더 안좋게 변해버립니다. dependent subquery는 똑같은데 subqery에서 index를 못타는 상황이 되어버리네요. semi join으로 변형시켜 보려고 그런건데 찾아보니 not in은 semi로 못바꾼다고 하네요.. left join으로 변형시키니 아래와 같이 나오고 상관subqery는 피해서 실행계획상은 좀 더 좋아진것도 같지만 실제수행시간은 비슷합니다.
SELECT 1 FROM A_TABLE A LEFT JOIN (SELECT DISTINCT SITE_NO, YR, MM, DT, EQPM_GB_CD, VISIT_IP FROM F_TABLE F ) F ON F.SITE_NO = A.SITE_NO AND F.YR = DATE_FORMAT(A.ACCESS_DTTM, '%Y') AND F.MM = DATE_FORMAT(A.ACCESS_DTTM, '%m') AND F.DT = DATE_FORMAT(A.ACCESS_DTTM, '%d') AND F.EQPM_GB_CD = CASE WHEN A.DEVICE_TYPE = 'P' THEN '11' WHEN A.DEVICE_TYPE = 'M' THEN '12' ELSE '99' END AND F.VISIT_IP = A.IP WHERE F.SITE_NO IS NULL;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | extra |
1 | PRIMARY | A | ALL | 2620137 | |||||
1 | PRIMARY | <derived2> | ref | <auto_key0> | <auto_key0> | 348 | A.SITE_NO,func,func | 10 | Using Where; Not exists; Using index |
2 | DERIVED | F | index | PRIMARY | PRIMARY | 348 | 34590 | Using index; Distinct |
2. SELECT절의 원래 구문은 많은 컬럼을 가져와서 가공해서 보여주고 있는 것이지만 너무 길어서 1로 생략을 하였습니다.
그리고 저 구문의 실제 결과 row는 현재는 0건입니다. 이부분을 이용해서 뭔가 방법이 있을 것 같은데 떠오를 듯 말 듯 합니다.;;;