简体   繁体   English

MySQL优化查询与子查询

[英]MySQL optimization query with subqueries

Today i received email from my hosting account saying that i need to tweak my query: 今天,我收到了来自托管帐户的电子邮件,说我需要调整查询:

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

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

This query examines 65,396,669,012,829 rows, which is unacceptable in shared hosting. 此查询检查65,396,669,012,829行,这在共享主机中是不可接受的。

tbh, i don't understand their explanation.. what the query actually does is to get 15 posts order by time updated, for each post i grab the latest comment, count all comments for each post. TBH,我不明白他们的解释..该查询的实际作用是按时间更新15个帖子的顺序,对于每个帖子,我都会获取最新评论,并计算每个帖子的所有评论。

posts table - 'the_data'

comments table = 'the_ans'

i'm not a mysql guru and i don't know how to improve this query any help will be appreciated 我不是mysql专家,我不知道如何改善此查询,我们将不胜感激

thx 谢谢

the query 查询

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 

this is the results structure 这是结果结构

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

A quick glance at the explain plan shows that there are no suitable indexes for MySQL to use, so it's resorting to full table scans. 快速浏览说明计划就会发现,没有适合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

To optimize the execution of the existing query, you need to add appropriate indexes. 为了优化现有查询的执行,您需要添加适当的索引。 Likely candidates: 可能的候选人:

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

Those indexes will significantly improve the performance of both the outer query (likely eliminating the sort operation), and the numerous executions of the correlated subqueries. 这些索引将显着提高外部查询(可能消除排序操作)以及相关子查询的大量执行的性能。


Beyond that, you're going to need to change the query to improve performance. 除此之外,您将需要更改查询以提高性能。 The LIMIT clause on the outermost query is being applied after the entire resultset is prepared, which means those two correlated subqueries are getting executed for every row in table the_data . 在准备完整个结果集之后,将应用最外层查询的LIMIT子句,这意味着the_datathe_data每一行执行这两个相关的子查询。 And that's going to eat your lunch, performance wise. 这就是吃午餐的时候,明智的选择。

To have those correlated subqueries run only for the (up to) 15 rows that are being returned, you need to get that LIMIT clause applied before those subqueries get run. 要使那些相关的子查询仅针对返回的(最多)15行运行,您需要在运行这些子查询之前应用LIMIT子句。

This query should return an equivalent resultset, and will avoid 34,000+ executions of each correlated subquery, which should improve performance considerably: 此查询应返回等效的结果集,并且将避免每个相关子查询的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

(Your current query executes each of those correlated subqueries " SELECT COUNT(1) FROM the_data " times. With the rewritten query above, each of those subqueries will be executed only 15 times.) (您当前的查询将执行每个相关子查询“ SELECT COUNT(1) FROM the_data ”次。使用上面重写的查询,这些子查询将仅执行15次。)

Perform the correlated subqueries after selecting the time-limited rows from the main query: 从主查询中选择有时间限制的行后,执行相关子查询:

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

Also, make sure you have indexes on time_updated and msg_id . 另外,请确保您在time_updatedmsg_id上具有索引。

Something like this should give you the result a bit quicker. 这样的事情应该可以使您更快地得到结果。

Note that this is using INNER JOINs as it is intended to work when every record on *the_data* has at least one matching record on *the_ans* 请注意,这是使用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 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM