1

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

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 专家,我不知道如何改进此查询任何帮助将不胜感激

谢谢

查询

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
4

3 回答 3

4

快速浏览一下解释计划表明没有合适的索引供 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在准备好整个结果集之后,将应用最外层查询的子句,这意味着这两个相关的子查询将针对 table 中的每一行执行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 次。)

于 2013-01-21T17:12:18.830 回答
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_updated和上有索引msg_id

于 2013-01-21T16:23:18.133 回答
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 
于 2013-01-21T17:10:06.330 回答