1、案例
create TABLE if not EXISTS `article`( `id` int(10) UNSIGNED not null primary key auto_increment, `author_id` int(10) UNSIGNED not null, `category_id` int(10) UNSIGNED not null, `views` int(10) UNSIGNED not null, `comments` int(10) UNSIGNED not null, `title` VARCHAR(255) not null, `content` TEXT not null ); INSERT into `article`(`author_id`,`category_id`,`views`,`comments`,`title`,`content`) VALUES (1,1,1,1,'1','1'), (2,2,2,2,'2','2'), (1,1,3,3,'3','3'); #查询category_id 为1 且comments 大于1 的情况下,views最多的情况下的article_id。
2、分析sql
explain SELECT id,author_id FROM article WHERE category_id = 1 AND comments > 1 ORDER BY views DESC LIMIT 1;
结论 :
#很显然,type是 ALL ,即最坏的现象。Extra里还出现了 Using filesort,也是最坏的情况。优化是必须的。
3、开始优化
# 1.1 新建索引 + 删除索引 #ALTER TABLE `article` ADD INDEX idx_article_ccv(`category_id`,`comments`,`views`); create index idx_article_ccv on article(category_id,comments,views); #explain 分析sql
结论 :
#type 变成 range , 这是可以接受的。但是extra里使用Using filesort 仍然是无法接受的。 #但是我们已经建立了索引,为啥没用呢? #这是因为按照BTree索引,为啥没用呢 ? #这是因为按照BTree 索引的工作原理, #先排序category_id, #如果遇到相同的category_id 则排序comments,如果遇到相同的comments则再排序views。 #当comments字段在联合索引里面处于中间位置时, #因为comments > 1 条件是一个范围值(所谓的range), #MySQL 无法利用索引再对后面的views 部分进行检索,即range类型查询字段后面的索引无效。
4、再次优化
#删除索引 drop index idx_article_ccv on article; #重建索引 create index idx_article_cv on article(category_id,views); #分析sql explain SELECT id,author_id FROM article WHERE category_id = 1 AND comments > 1 ORDER BY views DESC LIMIT 1;
结论:
#可以看出,type 变为了ref,Extra 中的Using filesort 也消失了,结果非常理想。
关注我的公众号,精彩内容不能错过