我尝试像这样优化查询:
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行。
很高兴听到有关此查询优化的任何想法。如果需要,我可以添加任何缺失的信息。
答案 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.