如何减少连接并使查询更加优化?

时间:2018-01-31 07:54:09

标签: mysql sql performance optimization

这是我的问题:

SELECT
   hh.id as question_id,
   h.id,
   IFNULL(hh.subject, h.subject) subject,
   h.amount,
   h.closed,
   h.AcceptedAnswer,
   h.related,
   h.type,
   h.date_time,
   (
      select
         COALESCE(sum(vv.value), 0) 
      from
         votes vv 
      where
         h.id = vv.post_id 
         and vv.table_code = 15
   )
   as total_votes,
   (
      select
         count(1) 
      from
         favorites ff 
      where
         IFNULL(hh.id, h.id) = ff.post_id 
         and ff.table_code = 15
   )
   as total_favorites,
   CASE
      WHEN
         f.id IS NOT NULL 
      THEN
         '1' 
      ELSE
         '0' 
   END
   AS you_marked_as_favorite 
FROM
   qanda h 
   LEFT JOIN
      qanda hh 
      ON h.related = hh.id 
   LEFT JOIN
      favorites f 
      ON IFNULL(hh.id, h.id) = f.post_id 
      AND f.user_id = ? 
      AND f.table_code = 15 
WHERE
   h.author_id = ? 
ORDER BY
   h.date_time DESC LIMIT 10;

我已将EXPLAIN用于查询,并根据以下内容创建了这些索引:

favorites(post_id, table_code, user_id)
votes(post_id, table_code)
qanda(related)
qanda(author_id, date_time)

但是对于庞大的数据集,它需要执行大约0.5sec。任何想法如何让它更快(更优化)

1 个答案:

答案 0 :(得分:1)

删除select子句中的相关子查询,而是连接到独立子查询。相关子查询是性能不佳的主要候选者。

SELECT
    hh.id question_id,
    h.id,
    IFNULL(hh.subject, h.subject) subject,
    h.amount,
    h.closed,
    h.AcceptedAnswer,
    h.related,
    h.type,
    h.date_time,
    t1.total_votes,
    t2.total_favorites,
    CASE WHEN f.id IS NOT NULL THEN '1' ELSE '0' END AS you_marked_as_favorite 
FROM qanda h 
LEFT JOIN qanda hh 
    ON h.related = hh.id 
LEFT JOIN favorites f 
    ON IFNULL(hh.id, h.id) = f.post_id AND
       f.user_id = ? AND
       f.table_code = 15
LEFT JOIN
(
    SELECT post_id, COALESCE(SUM(value), 0) AS total_votes
    FROM votes
    WHERE table_code = 15
    GROUP BY post_id
) t1
    ON h.id = t1.post_id
LEFT JOIN
(
    SELECT post_id, COUNT(*) AS total_favorites
    FROM favorites
    WHERE table_code = 15
    GROUP BY post_id
) t2
    ON IFNULL(hh.id, h.id) = t2.post_id 
WHERE
    h.author_id = ? 
ORDER BY
   h.date_time DESC
LIMIT 10;