mysql(mariadb) 쿼리 튜닝 질문드립니다~! 0 6 3,135

by 릿죠로 [MySQL] query tunning mysql mariadb optimize [2016.12.01 14:48:19]


안녕하세요 . 

다음과 같이 기사 작성자의 검색조건으로 하는 쿼리가 있습니다.

어떻게 하면 효율적으로 쿼리 튜닝이 가능할지 고수님들 의견 부탁드립니다!

추가로 이 쿼리에서 exists 부분에 한번더 서브쿼리가 들어갈수도 있을거 같습니다.

 

-- EXPLAIN extended
   SELECT *,
          (SELECT group_concat(`tag`)
           FROM `tb_webzine_tag` AS `tags`
           WHERE `tags`.`idx` = `news`.`idx`)
             AS `tags`,
          (SELECT group_concat(`sportsname`)
           FROM `tb_info_sports` AS `isports`
           WHERE `idx` IN (SELECT `sportsidx`
                           FROM `tb_webzine_sports` AS `wsports`
                           WHERE `wsports`.`idx` = `news`.`idx`))
             AS `sports`,
          (SELECT concat('[',
                         group_concat(concat('{"idx":',
                                             `idx`,
                                             ',"name":"',
                                             `sportsname`,
                                             '","icon":"',
                                             `icon`,
                                             '"}')),
                         ']')
           FROM `tb_info_sports` AS `isports`
           WHERE `idx` IN (SELECT `sportsidx`
                           FROM `tb_webzine_sports` AS `wsports`
                           WHERE `wsports`.`idx` = `news`.`idx`))
             AS `sportsinfo`
   FROM `webzine_news`    AS `news`
        INNER JOIN
        (SELECT `news`.`idx`, `content`.`subject`
         FROM `tb_webzine_news`      AS `news`
              INNER JOIN
              (SELECT `idx`, `subject` FROM `tb_webzine_content`)
              AS `content`
                 ON `news`.`idx` = `content`.`idx`
         WHERE     `state` = 'Y'
               AND EXISTS
                      (SELECT `idx`
                       FROM `tb_webzine_author` AS `t`
                       WHERE     `news`.`idx` = `t`.`idx`
                             AND `author` = (SELECT `idx`
                                             FROM `tb_reporter`
                                             WHERE `author` = 'Shin Ji Hoon' )
                       ORDER BY NULL)
         ORDER BY `postdate` DESC
          LIMIT 30 OFFSET 0
         ) AS `filter`
           ON `news`.`idx` = `filter`.`idx`;

 

----------------------------------------------------------------------------------------------------------------------

실행계획)

id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY   ALL         30 100  
1 PRIMARY news eq_ref PRIMARY,idx PRIMARY 4 filter.idx 1 100  
7 DERIVED news ref PRIMARY,recent,top_comment recent 1 const 466 100 Using where; Using index
7 DERIVED webzine_content eq_ref PRIMARY PRIMARY 4 db_sports.news.idx 1 100  
9 DEPENDENT SUBQUERY t eq_ref PRIMARY,author PRIMARY 8 db_sports.news.idx,const 1 100 Using where; Using index
10 SUBQUERY reporter ref name name 767 const 1 100 Using where; Using index
5 DEPENDENT SUBQUERY wsports ref PRIMARY,sportsidx PRIMARY 4 db_sports.news.idx 1 100 Using index
5 DEPENDENT SUBQUERY isports eq_ref PRIMARY PRIMARY 4 db_sports.wgame.gameidx 1 100  
3 DEPENDENT SUBQUERY wsports ref PRIMARY,sportsidx PRIMARY 4 db_sports.news.idx 1 100 Using index
3 DEPENDENT SUBQUERY isports eq_ref PRIMARY PRIMARY 4 db_sports.wgame.gameidx 1 100  
2 DEPENDENT SUBQUERY tags ref PRIMARY PRIMARY 4 db_sports.news.idx 3 100 Using index

 

by 마농 [2016.12.01 15:07:44]

IN 절과 EXISTS 절이 많이 사용되는데
서브쿼리보다는 조인방식으로 변경하는것이 좋을 듯 합니다.
특히나 유일한 조건절인 기자명이 EXISTS 서브쿼리 안에 있네요.
이 조건을 밖으로 빼내어 조인 형식으로 해야 합니다.


by 릿죠로 [2016.12.01 15:19:41]

마농님 안녕하세요 항상 도움 많이 받고있습니다!

다음과같이 변경한다면 추가로 튜닝할 부분은 없을까요?

 

EXPLAIN
   SELECT *,
          (SELECT group_concat(`tag`)
           FROM `tb_webzine_tag` AS `tags`
           WHERE `tags`.`idx` = `news`.`idx`)
             AS `tags`,
          (SELECT group_concat(`sportsname`)
           FROM `tb_info_sports` AS `isports`
           WHERE `idx` IN (SELECT `sportsidx`
                           FROM `tb_webzine_sports` AS `wsports`
                           WHERE `wsports`.`idx` = `news`.`idx`))
             AS `sports`,
          (SELECT concat('[',
                         group_concat(concat('{"idx":',
                                             `idx`,
                                             ',"name":"',
                                             `sportsname`,
                                             '","icon":"',
                                             `icon`,
                                             '"}')),
                         ']')
           FROM `tb_info_sports` AS `isports`
           WHERE `idx` IN (SELECT `sportsidx`
                           FROM `tb_webzine_sports` AS `wsports`
                           WHERE `wsports`.`idx` = `news`.`idx`))
             AS `sportsinfo`
   FROM `tb_webzine_news`    AS `news`
        INNER JOIN
        (SELECT `news`.`idx`, `content`.`subject`
         FROM `tb_webzine_news`      AS `news`
              INNER JOIN
              (SELECT `idx`, `subject` FROM `tb_webzine_content`)
              AS `content`
                 ON `news`.`idx` = `content`.`idx`
              INNER JOIN (SELECT `idx`
                          FROM `tb_webzine_author`
                          WHERE `author` = (SELECT `idx`
                                            FROM `tb_reporter`
                                            WHERE `author` = ?
                                            ORDER BY NULL)) AS `author`
                 ON `news`.`idx` = `author`.`idx`
         WHERE `state` = ?
         ORDER BY `postdate` DESC
         LIMIT 30
         OFFSET 0) AS `filter`
           ON `news`.`idx` = `filter`.`idx`;


by 마농 [2016.12.01 15:30:53]

1. Exists 연관서브쿼리(dependent subquery)의 종속관계를 끊고 이퀄 서브쿼리로 바꾼 것은 좋은 방향입니다.
  - 하지만 서브쿼리에 서브쿼리를 거듭하는 것은 개선이 필요해 보입니다.
2. content 조인 후 필터링 하는 것은
  - 필터링 후 조인하는 방법으로 바꾸셔야 합니다.
3. 페이징 쿼리의 정렬기준은 좀더 명확해야 합니다.
  - 중복 없는 유니크키가 정렬에 포함되어야 합니다.

(
SELECT `news`.`idx`
  FROM `tb_webzine_news`       AS `news`
 INNER JOIN `tb_webzine_autho` AS `auth`
    ON `news`.`idx` = `auth`.`idx`
 INNER JOIN `tb_reporter`      AS `rptr`
    ON `auth`.`author` = `rptr`.`idx`
 WHERE `news`.`state`  = 'Y'
   AND `rptr`.`author` = 'Shin Ji Hoon'
 ORDER BY `news`.`postdate` DESC
        , `news`.`idx`      DESC
 LIMIT 30 OFFSET 0
) AS `filter`

 


by 릿죠로 [2016.12.01 18:31:05]

답변 매우 감사합니다~.마농님 위 쿼리에서 order by 절을 좀 더 튜닝할 방법은 없을까요?


by 마농 [2016.12.01 18:47:28]

각 테이블의 PK 및 인덱스 정보를 알려주세요.


by 마농 [2016.12.02 10:16:01]

기자 이름(tb_reporter.author)에 인덱스가 있어야 할 듯 하구요.
등록 기자(tb_webzine_autho.author)에도 인덱스가 있어야 하겠네요.
일자로 정렬하는데 그냥 idx 로 정렬하면 안되는지를 확인해 보세요.
어차피 등록 순서대로 idx 가 증가할 테니 굳이 일자로 정렬 안해도 될 듯 싶네요.
만약 정렬 조건을 일자가 아닌 idx 로 바꾼다면?
테이블 news 에 대한 조인 없이 tb_webzine_autho.idx 로만 페이징처리 해도 되겠네요.


tb_webzine_autho 의 인덱스만으로 정렬효과를 얻으려면?
 - tb_webzine_autho(author, idx) 인덱스가 필요합니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입