0

私はメッセージ ボードを作成しており、通常のトピック (つまり、貼り付けられていないトピック) を取得して、最後に投稿されたメッセージの日付で並べ替えようとしています。これを達成することはできますが、約 10,000 件のメッセージと 1500 件のトピックがある場合、クエリ時間は 60 秒を超えます。

私の質問は、パフォーマンスを向上させるためにクエリにできることはありますか、それとも設計に根本的な欠陥がありますか?

これが私が使用しているクエリです。

SELECT Messages.topic_id,
       Messages.posted,
       Topics.title,
       Topics.user_id,
       Users.username
FROM Messages
LEFT JOIN
  Topics USING(topic_id)
LEFT JOIN
   Users on Users.user_id = Topics.user_id
WHERE Messages.message_id IN (
    SELECT MAX(message_id)
    FROM Messages
    GROUP BY topic_id)
AND Messages.topic_id
NOT IN (
    SELECT topic_id
    FROM StickiedTopics)
AND Messages.posted IN (                           
    SELECT MIN(posted)
    FROM Messages 
    GROUP BY message_id)
AND Topics.board_id=1
ORDER BY Messages.posted DESC LIMIT 50

編集ここに説明計画があります

+----+--------------------+----------------+----------------+------------------+----------+---------+-------------------------+------+----------------------------------------------+
| id | select_type        | table          | type           | possible_keys    | key      | key_len | ref                     | rows | Extra                                        |
+----+--------------------+----------------+----------------+------------------+----------+---------+-------------------------+------+----------------------------------------------+
|  1 | PRIMARY            | Topics         | ref            | PRIMARY,board_id | board_id | 4       | const                   |  641 | Using where; Using temporary; Using filesort |
|  1 | PRIMARY            | Users          | eq_ref         | PRIMARY          | PRIMARY  | 4       | spergs3.Topics.user_id  |    1 |                                               |
|  1 | PRIMARY            | Messages       | ref            | topic_id         | topic_id | 4       | spergs3.Topics.topic_id |    3 | Using where                                   |
|  4 | DEPENDENT SUBQUERY | Messages       | index          | NULL             | PRIMARY  | 8       | NULL                    |    1 |                                              |
|  3 | DEPENDENT SUBQUERY | StickiedTopics | index_subquery | topic_id         | topic_id | 4       | func                    |    1 | Using index                                  |
|  2 | DEPENDENT SUBQUERY | Messages       | index          | NULL             | topic_id | 4       | NULL                    |    3 | Using index                                  |
+----+--------------------+----------------+----------------+------------------+----------+---------+-------------------------+------+----------------------------------------------+

インデックス

+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table    | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Messages |          0 | PRIMARY  |            1 | message_id  | A         |        9956 |     NULL | NULL   |      | BTREE      |         |
| Messages |          0 | PRIMARY  |            2 | revision_no | A         |        9956 |     NULL | NULL   |      | BTREE      |         |
| Messages |          1 | user_id  |            1 | user_id     | A         |         432 |     NULL | NULL   |      | BTREE      |         |
| Messages |          1 | topic_id |            1 | topic_id    | A         |        3318 |     NULL | NULL   |      | BTREE      |         |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table  | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Topics |          0 | PRIMARY  |            1 | topic_id    | A         |        1205 |     NULL | NULL   |      | BTREE      |         |
| Topics |          1 | user_id  |            1 | user_id     | A         |         133 |     NULL | NULL   |      | BTREE      |         |
| Topics |          1 | board_id |            1 | board_id    | A         |           1 |     NULL | NULL   |      | BTREE      |         |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

+-------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name        | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Users |          0 | PRIMARY         |            1 | user_id     | A         |        2051 |     NULL | NULL   |      | BTREE      |         |
| Users |          0 | username_UNIQUE |            1 | username    | A         |        2051 |     NULL | NULL   |      | BTREE      |         |
+-------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
4

2 に答える 2

2

資格のあるトピックの最初の基礎から始めて、それらの ID を取得し、その後参加します。私の内側の最初のクエリは、topic_id と最大メッセージでグループ化された事前修飾を行い、事前修飾された個別の ID を取得します。stickiesTopics にも LEFT JOIN を適用しました。なんで?左結合を行うことで、見つかったもの (除外したいもの) を探すことができます。そこで、Stickies トピック ID が NULL の WHERE 句を適用しました (つまり、見つかりませんでした)。したがって、これを行うことで、いくつかのネストされたサブクエリを実行することなく、リストを大幅にペアダウンできました。その結果から、メッセージ、トピック (board_id = 1 の修飾子を含む)、ユーザーに参加し、必要に応じてパーツを取得できます。最後に、MIN(posted) 修飾子に単一の WHERE IN サブセレクトを適用します。その根拠はわかりませんが、元のクエリの一部として残しました。

SELECT STRAIGHT_JOIN
      M.topic_id,
      M.posted,
      T.title,
      T.user_id,
      U.username
   FROM 
      ( select 
              M1.Topic_ID, 
              MAX( M1.Message_id ) MaxMsgPerTopic
           from 
              Messages M1
                 LEFT Join StickiedTopics ST
                    ON M1.Topic_ID = ST.Topic_ID
           where
              ST.Topic_ID IS NULL
           group by 
              M1.Topic_ID ) PreQuery
        JOIN Messages M
           ON PreQuery.MaxMsgPerTopic = M.Message_ID
           JOIN Topics T
               ON M.Topic_ID = T.Topic_ID
              AND T.Board_ID = 1
              LEFT JOIN Users U
                 on T.User_ID = U.user_id 
   WHERE
      M.posted IN ( SELECT MIN(posted)
                       FROM Messages 
                       GROUP BY message_id)
   ORDER BY 
      M.posted DESC 
   LIMIT 50
于 2012-03-14T03:14:42.960 に答える
1

あなたの問題の大部分はサブクエリにあると思います。次のようなことを試してください:

SELECT Messages.topic_id,
       Messages.posted,
       Topics.title,
       Topics.user_id,
       Users.username
FROM Messages
LEFT JOIN
    Topics USING(topic_id)
LEFT JOIN
    StickiedTopics ON StickiedTopics.topic_id = Topics.topic_id 
                   AND StickedTopics.topic_id IS NULL
LEFT JOIN
    Users on Users.user_id = Topics.user_id
WHERE Messages.message_id IN (
    SELECT MAX(message_id)
    FROM Messages m1
    WHERE m1.topic_id = Messages.topic_id)
AND Messages.posted IN (                           
    SELECT MIN(posted)                                                                                           
    FROM Messages m2
    GROUP BY message_id)
AND Topics.board_id=1
ORDER BY Messages.posted DESC LIMIT 50

グループ化を削除して、最初のサブクエリを最適化しました。2 番目のサブクエリは、に置き換えることができるため不要でしたJOIN

この 3 番目のサブクエリが何をすべきかよくわかりません。

AND Messages.posted IN (                           
    SELECT MIN(posted)                                                                                           
    FROM Messages m2
    GROUP BY message_id)

それが何をすべきかを知っていれば、これを最適化するのに役立つかもしれません。正確には何ですかposted- 日付、整数など? それは何を表していますか?

于 2012-03-14T02:47:30.533 に答える