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

Explainプランをひと目見ると、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句は、結果セット全体が準備された後に適用されます。つまり、これら2つの相関するサブクエリは、テーブルのすべての行に対して実行されます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

このようなものを使用すると、結果が少し速くなります。

これは、*the_data*のすべてのレコードに*the_ans*に少なくとも1つの一致するレコードがある場合に機能することを目的としているため、INNERJOINを使用していることに注意してください。

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 に答える