如何优化这种缓慢的MySQL查询 - 后期行查找?

时间:2015-02-03 12:34:39

标签: mysql innodb

我将网站转换为使用XenForo作为论坛软件,但是这个网站在MySQL表中有数百万个线程行。如果我尝试浏览一个分页的线程列表,那么我走得越远就越慢。一旦我在第10,000页,它需要将近30秒。

我的目标是改进下面的查询,可能通过使用后期行查找,以便我可以更快地运行此查询:

SELECT thread.*
    ,
    user.*, IF(user.username IS NULL, thread.username, user.username) AS username,
    NULL AS thread_read_date,
    0 AS thread_is_watched,
    0 AS user_post_count
FROM xf_thread AS thread

    LEFT JOIN xf_user AS user ON
        (user.user_id = thread.user_id)
WHERE (thread.node_id = 152) AND (thread.sticky = 0) AND (thread.discussion_state IN ('visible'))
ORDER BY thread.last_post_date DESC
LIMIT 20 OFFSET 238340

Run Time: 4.383607

Select Type    Table    Type    Possible Keys    Key    Key Len    Ref    Rows    Extra      
SIMPLE    thread    ref    node_id_last_post_date,node_id_sticky_state_last_post    node_id_last_post_date    4    const    552480    Using where      
SIMPLE    user    eq_ref    PRIMARY    PRIMARY    4    sitename.thread.user_id    1   

架构:

CREATE TABLE `xf_thread` (
  `thread_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `node_id` INT(10) UNSIGNED NOT NULL,
  `title` VARCHAR(150) NOT NULL,
  `reply_count` INT(10) UNSIGNED NOT NULL DEFAULT '0',
  `view_count` INT(10) UNSIGNED NOT NULL DEFAULT '0',
  `user_id` INT(10) UNSIGNED NOT NULL,
  `username` VARCHAR(50) NOT NULL,
  `post_date` INT(10) UNSIGNED NOT NULL,
  `sticky` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
  `discussion_state` ENUM('visible','moderated','deleted') NOT NULL DEFAULT 'visible',
  `discussion_open` TINYINT(3) UNSIGNED NOT NULL DEFAULT '1',
  `discussion_type` VARCHAR(25) NOT NULL DEFAULT '',
  `first_post_id` INT(10) UNSIGNED NOT NULL,
  `first_post_likes` INT(10) UNSIGNED NOT NULL DEFAULT '0',
  `last_post_date` INT(10) UNSIGNED NOT NULL,
  `last_post_id` INT(10) UNSIGNED NOT NULL,
  `last_post_user_id` INT(10) UNSIGNED NOT NULL,
  `last_post_username` VARCHAR(50) NOT NULL,
  `prefix_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
  `sonnb_xengallery_import` TINYINT(3) DEFAULT '0',
  PRIMARY KEY (`thread_id`),
  KEY `node_id_last_post_date` (`node_id`,`last_post_date`),
  KEY `node_id_sticky_state_last_post` (`node_id`,`sticky`,`discussion_state`,`last_post_date`),
  KEY `last_post_date` (`last_post_date`),
  KEY `post_date` (`post_date`),
  KEY `user_id` (`user_id`)
) ENGINE=INNODB AUTO_INCREMENT=2977 DEFAULT CHARSET=utf8

任何人都可以帮我提高此查询的速度吗?我是一个真正的MySQL新手,但我在其他论坛软件上运行相同的数据集,而且速度要快得多 - 所以我确定有某种方式。这张表是INNODB,我认为服务器已经过优化。

2 个答案:

答案 0 :(得分:0)

您的用户表已经按用户ID索引......好。

对于你的线程表,我会在其上有一个带有键的复合索引

(note_id,sticky,discussion_state,last_post_date)

这样,索引在WHERE子句中的所有部分上都进行了优化...因为它也具有last_post_date,所以ORDER BY子句可以使用它。 Order By子句因查杀性能而臭名昭着。

答案 1 :(得分:0)

这可能会有所帮助:http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/

概念是,只查询具有所需分页/排序的索引列,然后将此列表连接到表中所需的其他列