使用ORDER BY帮助优化MySQL SELECT

时间:2011-07-12 21:12:57

标签: mysql indexing

目前该表具有以下索引:

  1. forum_id_index
  2. other_forum_id_index
  3. forum_id_on_other_forum_id_index => [forum_id,other_forum_id]
  4. 查询:

    SELECT `topics.*` 
    FROM `topics` 
    WHERE (table.forum_id = ? OR table.other_forum_id = ?) 
    ORDER by sticky, replied_at DESC LIMIT 25
    

    我尝试在以下内容中添加索引:

    1. 粘性
    2. replied_at
    3. [sticky,replied_at]
    4. [forum_id,other_forum_id,sticky,replied_at]
    5. [sticky,replied_at,forum_id,other_forum_id]
    6. 这是一个论坛,试图在论坛中获得前25个主题,但在顶部放置sticky主题(粘性是粘性/非粘性的二进制字段)。

      我已经阅读了很多关于优化ORDER BY的所有内容,但没有运气。这是MySQL 5.1, INNODB。任何帮助将不胜感激。

      EDITS

      根据评论中的要求(对不起,如果我做错了 - 在SU上发布新内容)。 EXPLAIN的结果:

        

      id = 1

           

      select_type = SIMPLE

           

      table = topics

           

      type = index_merge

           

      possible_keys = index_topics_on_forum_id,index_topics_on_sticky_and_replied_at,index_topics_on_forum_id_and_replied_at,index_topics_on_video_forum_id,index_forum_id_on_video_forum_id,

           

      keys = index_topics_on_forum_id,index_topics_on_video_forum_id

           

      key_len = 5,5

           

      ref = NULL

           

      rows = 13584

           

      Extra =使用union(index_topics_on_forum_id,index_topics_on_video_forum_id);用在哪里;使用filesort

      SHOW INDEXES FROM主题返回https://gist.github.com/1079454 - 无法在此处显示格式。

      编辑2

      SELECT `topics`.*
      FROM `topics`
      WHERE topics.forum_id=4
      ORDER BY sticky desc, replied_at DESC
      

      跑得非常快(1.4毫秒)。当我将topics.forum_id更改为topics.video_forum_id时,查询也是如此 - 只是当我在查询中使用or时,查询时才会这样。

4 个答案:

答案 0 :(得分:1)

我认为这应该非常快。

索引:

ALTER TABLE `topics` 
    ADD INDEX `forum` (`forum_id` ASC, `sticky` ASC, `replied_at` DESC), 
    ADD INDEX `other_forum` (`other_forum_id` ASC, `sticky` ASC, `replied_at` DESC);

查询:

(
    SELECT `topics.*` 
    FROM `topics` USE INDEX (`forum`)
    WHERE `topics`.forum_id = ?
    ORDER by sticky, replied_at DESC 
    LIMIT 25
) UNION (
    SELECT `topics.*` 
    FROM `topics` USE INDEX (`other_forum`)
    WHERE `topics`.other_forum_id = ?
    ORDER by sticky, replied_at DESC 
    LIMIT 25
)
ORDER by sticky, replied_at DESC 
LIMIT 25

答案 1 :(得分:0)

尝试索引[forum_id,sticky,replied_at desc]和[other_forum_id,sticky,replied_at desc]

您可以尝试将查询写为联合:

    SELECT `topics.*` FROM `topics` WHERE (table.forum_id = ?)
UNION
SELECT `topics.*` FROM `topics` WHERE (table.other_forum_id = ?)
 ORDER by sticky, replied_at DESC LIMIT 25

答案 2 :(得分:0)

使用MySQL的EXPLAIN命令了解与查询相关的费用:

EXPLAIN SELECT ...

注意表扫描,这可能是昂贵的。

此外,MySQL可能会也可能不会使用索引。这完全取决于查询优化器如何理解您的查询。

FORCE INDEX可能会有所帮助,因为这个选项告诉MySQL,表扫描将是超级昂贵的。看看here

答案 3 :(得分:0)

您可以尝试两件事:

  • 一个,索引在:

    • (forum_id, sticky, replied_at)
    • (other_forum_id, sticky, replied_at)

使用您的原始查询或Karolis的建议或

  • 二,索引在:

    • (forum_id)
    • (other_forum_id)
    • (sticky, replied_at)