안녕하세요 .
다음과 같이 기사 작성자의 검색조건으로 하는 쿼리가 있습니다.
어떻게 하면 효율적으로 쿼리 튜닝이 가능할지 고수님들 의견 부탁드립니다!
추가로 이 쿼리에서 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 |
마농님 안녕하세요 항상 도움 많이 받고있습니다!
다음과같이 변경한다면 추가로 튜닝할 부분은 없을까요?
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`;
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`
기자 이름(tb_reporter.author)에 인덱스가 있어야 할 듯 하구요.
등록 기자(tb_webzine_autho.author)에도 인덱스가 있어야 하겠네요.
일자로 정렬하는데 그냥 idx 로 정렬하면 안되는지를 확인해 보세요.
어차피 등록 순서대로 idx 가 증가할 테니 굳이 일자로 정렬 안해도 될 듯 싶네요.
만약 정렬 조건을 일자가 아닌 idx 로 바꾼다면?
테이블 news 에 대한 조인 없이 tb_webzine_autho.idx 로만 페이징처리 해도 되겠네요.
tb_webzine_autho 의 인덱스만으로 정렬효과를 얻으려면?
- tb_webzine_autho(author, idx) 인덱스가 필요합니다.