【问题标题】:How can I reduce joins and make the query more optimal?如何减少连接并使查询更优化?
【发布时间】:2018-01-31 07:54:08
【问题描述】:

这是我的查询:

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。知道如何让它更快(更优化)吗?

【问题讨论】:

  • ON IFNULL(hh.id, h.id) = f.post_id 似乎非常奇怪。请解释它并证明需要LEFT

标签: mysql sql performance optimization


【解决方案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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 2020-02-10
    • 2021-07-22
    • 2011-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多