2013-01-21 75 views
0

今天,我收到的电子邮件从我的托管帐户说,我需要调整我的查询:与子查询的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 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 
+0

您确定'LIMIT 26340,15'部分? – inhan

+1

基本的问题是需要执行查询来获得15行。要执行你的主查询,每个子查询都需要为每一行处理执行。你可以发布每个表的show create table的结果吗?你是否在每个表中创建了“id”的索引? – Jaydee

+0

通常,不相关的子查询将比关联的子查询执行得更好。通用语法如下:SELECT x。* FROM my_table x JOIN(SELECT id,MAX(time)max_time FROM my_table GROUP BY id)y ON y.id = x.id AND y.max_time = x.time;这将在每个线程中为您提供最新的消息。然后,你只需加入其他信息(或反之亦然) – Strawberry

回答

2

在解释计划快速浏览显示,没有适合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次。)

+0

那好吧,似乎最大的问题是我没有使用索引。 也使用你的方法时,查询执行速度大约快16%。 thx! – eben

+0

当我们每天增加约1000%的指数时,我们会学到新的东西 – eben

+0

@JQman:是的,没有索引是最大的问题。这是一个修复程序,可以在不部署任何代码更改的情况下应用。对于添加了这些索引的查询,获取EXPLAIN输出将会很好。 – spencer7593

1

执行相关子查询从主查询选择时间限制的行:

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指标。

0

像这样的东西应该会让你的结果更快一点。

注意,这是使用内部联接,因为它的目的是工作,当上* 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