带子查询的MySQL优化查询

时间:2013-01-21 15:38:48

标签: mysql query-optimization subquery

今天我收到了来自我的托管帐户的电子邮件,说我需要调整我的查询:

SELECT
  `id`, `nick`, `msg`, `uid`, `show_pic`,
  `time`,`ip`,`time_updated`,
  (SELECT COUNT(c.msg_id)
   FROM `the_ans` c
   where c.msg_id = d.id) AS counter,
  (SELECT c.msg
   FROM `the_ans` c
   WHERE c.msg_id=d.id
   ORDER BY `time` DESC LIMIT 1) as lastmsg
FROM
  `the_data` d
ORDER BY `time_updated` DESC LIMIT 26340 ,15

说明:

id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY d ALL 34309 Using filesort
3 DEPENDENT SUBQUERY c ALL 43659 Using where; Using filesort
2 DEPENDENT SUBQUERY c ALL 43659 Using where
  

此查询检查65,396,669,012,829行,这在共享主机中是不可接受的。

tbh,我不明白他们的解释.. 查询实际上做的是按时间顺序更新15个帖子, 对于每个帖子,我抓住最新的评论, 计算每篇文章的所有评论。

posts table - 'the_data'

comments table = 'the_ans'

我不是一个mysql大师,我不知道如何改进这个查询 任何帮助将不胜感激

THX

查询

SELECT
  `id` , `nick` , `msg` , `uid` , `show_pic` , `time` , `ip` , `time_updated` , (
    SELECT COUNT( c.msg_id )
    FROM `the_ans` c
    WHERE c.msg_id = d.id
   ) AS counter, (
    SELECT c.msg
    FROM `the_ans` c
    WHERE c.msg_id = d.id
    ORDER BY `time` DESC
    LIMIT 1
   ) AS lastmsg
FROM `the_data` d
ORDER BY `time_updated` DESC
LIMIT 26340 , 15 

这是结果结构

id| nick  | msg  | uid   | show_pick | time      | ip |time_updated|counter|lastmsg
  |       |      |       |           |           |    |            |       |
7 | jqman | hello| 10074 |   0       |2013-21-01 | 12 |2013-21-01  | 55    |blah bl

3 个答案:

答案 0 :(得分:3)

快速浏览解释计划表明,MySQL没有合适的索引可供使用,因此它采用全表扫描。

 EXPLAIN: 
 id select_type        table type possible_keys key key_len ref rows  Extra 
 -- ------------------ ----- ---- ------------- --- ------- --- ----- ---------------------------- 
 1  PRIMARY            d     ALL                                34309 Using filesort
 3  DEPENDENT SUBQUERY c     ALL                                43659 Using where; Using filesort 
 2  DEPENDENT SUBQUERY c     ALL                                43659 Using where

要优化现有查询的执行,需要添加适当的索引。可能的候选人:

ON `the_data`(`time_updated`)
ON `the_ans`(`msg_id`,`time`)

这些索引将显着提高外部查询(可能消除排序操作)的性能,以及相关子查询的大量执行。


除此之外,您还需要更改查询以提高性能。在准备整个结果集之后,将应用最外层查询的LIMIT子句,这意味着将为表the_data中的每一行执行这两个相关子查询。这将是你的午餐,表现明智。

要使这些相关子查询仅针对返回的(最多)15行运行,您需要在这些子查询运行之前应用LIMIT子句。

此查询应返回等效的结果集,并且将避免每个相关子查询的34,000多次执行,这应该会显着提高性能:

SELECT d.*
     , ( SELECT COUNT( c.msg_id )
           FROM `the_ans` c
          WHERE c.msg_id = d.id
       ) AS counter
     , ( SELECT c.msg
           FROM `the_ans` c
          WHERE c.msg_id = d.id
          ORDER BY `time` DESC
          LIMIT 1
       ) AS lastmsg
  FROM ( SELECT e.`id` 
              , e.`nick`
              , e.`msg`
              , e.`uid`
              , e.`show_pic`
              , e.`time`
              , e.`ip`
              , e.`time_updated` 
           FROM `the_data` e
          ORDER
             BY e.`time_updated` DESC
          LIMIT 26340 , 15 
       ) d
 ORDER BY d.`time_updated` DESC

(您当前的查询执行每个相关子查询“SELECT COUNT(1) FROM the_data”次。通过上面的重写查询,每个子查询只执行15次。)

答案 1 :(得分:2)

在从主查询中选择限时行后执行相关子查询

SELECT d.*,
       (SELECT COUNT(c.msg_id)
        FROM `the_ans` c
        where c.msg_id = d.id) AS counter,
       (SELECT c.msg
        FROM `the_ans` c
        WHERE c.msg_id=d.id
        ORDER BY `time` DESC LIMIT 1) as lastmsg
FROM (SELECT
        `id`, `nick`, `msg`, `uid`, `show_pic`,
        `time`,`ip`,`time_updated`
      FROM
        `the_data`
      ORDER BY `time_updated` DESC LIMIT 26340 ,15) d

另外,请确保您在time_updatedmsg_id上有索引。

答案 2 :(得分:0)

这样的事情会让你的结果更快一些。

请注意,这是使用INNER JOIN,因为当* the_data *上的每条记录在* the_ans *

上至少有一条匹配记录时,它可以正常工作
SELECT `id` , `nick` , `msg` , `uid` , `show_pic` , `time` , `ip` , `time_updated` , Sub1.counter, c.msg AS lastmsg
FROM `the_data` d
INNER JOIN (SELECT msg_id, COUNT( * ) AS counter, MAX( `time` ) AS MaxTime FROM `the_ans` GROUP BY msg_id) Sub1 ON d.id = Sub1.msg_id
INNER JOIN the_ans c ON d.id = c.msg_id AND sub1.MaxTime = c.`time`
ORDER BY `time_updated` DESC
LIMIT 26340 , 15