Optimizan ORDER BY& MySQL中的LIMIT查询

时间:2016-10-09 19:53:50

标签: mysql query-optimization

我尝试像这样优化查询:

SELECT sql_no_cache t.topic_id 
FROM   blog AS b, 
       topic AS t 
WHERE  t.topic_publish = 1 
       AND t.topic_type <> 'topic' 
       AND t.topic_lang = 'en' 
       AND t.blog_id = b.blog_id 
ORDER  BY t.topic_date_add DESC 
LIMIT  50;

架构:

CREATE TABLE `topic` (
  `topic_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `blog_id` int(11) unsigned NOT NULL,
  `user_id` int(11) unsigned NOT NULL,
  `topic_type` enum('topic_catalog','topic','link','question','photoset') NOT NULL DEFAULT 'topic',
  `topic_lang` varchar(16) NOT NULL DEFAULT 'russian',
  `topic_title` varchar(200) NOT NULL,
  `topic_date_add` datetime NOT NULL,
  `topic_date_edit` datetime DEFAULT NULL,
  `topic_publish` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`topic_id`),
  UNIQUE KEY `topic_date_add`     (`topic_type`,`topic_lang`,`topic_publish`,`blog_id`,`topic_id`,`topic_date_add`),
  KEY `blog_id` (`blog_id`),
  KEY `user_id` (`user_id`),
  KEY `topic_date_add` (`topic_date_add`,`topic_type`),
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

topic包含大约1M条记录,并且在没有ORDER BY的情况下效果非常好(约0.0016秒)。

ORDER BY t.topic_date_add DESC查询执行时间更长(在同一台机器上约为2.8083)

查询Explain

order如下:

+----+-------------+-------+--------+----------------------+----------------+---------+--------------------+------+-------------+
| id | select_type | table | type   | possible_keys        | key            | key_len | ref                | rows | Extra       |
+----+-------------+-------+--------+----------------------+----------------+---------+--------------------+------+-------------+
|  1 | SIMPLE      | t     | index  | blog_id,topic_rating | topic_date_add | 9       | NULL               |   50 | Using where |
|  1 | SIMPLE      | b     | eq_ref | PRIMARY,blog_type    | PRIMARY        | 4       | sku_prod.t.blog_id |    1 | Using where |
+----+-------------+-------+--------+----------------------+----------------+---------+--------------------+------+-------------+

我是查询优化的新手,无法理解为什么查询与订单执行这么久。从Explain看起来只执行了50行。

很高兴听到有关此查询优化的任何想法。如果需要,我可以添加任何缺失的信息。

2 个答案:

答案 0 :(得分:1)

首先,学会使用正确的,明确的JOIN语法:

SELECT sql_no_cache t.topic_id 
FROM blog b JOIN
     topic t
     ON t.blog_id = b.blog_id
WHERE t.topic_publish = 1 
      t.topic_type <> 'topic' 
      t.topic_lang = 'en'  
ORDER BY t.topic_date_add DESC 
LIMIT 50;

对于此查询,最佳索引为topic(topic_lang, topic_publish, topic_type, blog_id, topic_date_add, topic_id)。最后两个密钥不会用于排序,但它们的包含使索引成为覆盖索引。

假设blog_id始终匹配blog中的内容,那么为什么不使用:

SELECT sql_no_cache t.topic_id 
FROM topic t
WHERE t.topic_publish = 1 
      t.topic_type <> 'topic' 
      t.topic_lang = 'en'  
ORDER BY t.topic_date_add DESC 
LIMIT 50;

相同的索引适用于此。

答案 1 :(得分:0)

我会投票赞成(在删除&#34之后的混乱;主题_&#34;):

第1步:

INDEX(publish, lang,   -- the '=' columns
      date_add,        -- hoping that the optimizer will move to ORDER BY
      type, blog_id, id)  -- for "covering"

如果它消耗ORDER BY,则不需要排序通行证。但是,由于type <> 'topic',它必须跳过不确定的行数。

第2步:也可以是UNIQUE而不是INDEX。而且,除非它会减慢其他查询速度,否则请扔掉UNIQUE

步骤3:然后,重新排列键以避免在辅助键和PRIMARY KEY&amp;之间弹跳。数据:

PRIMARY KEY(.. those 6 columns ..),  -- for "clustering"
INDEX(id),   -- To keep AUTO_INCREMENT happy.
...   -- any other keys you still need.