MySQL索引优化(一)查询索引

一、单表

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       varbinary(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');

执行查询

select * from article;

结果如下
在这里插入图片描述
现有以下要求
查询category_id为1且comments大于1的情况下,views最多的article_id。
查询语句如下

select id, author_id from article where category_id = 1 and comments > 1 order by views DESC limit 1;

结果如下
在这里插入图片描述
sql语句加上explain,执行如下

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,也是最坏的情况。优化是必须的。

2、优化查询

创建索引

create index idx_article_ccv on article(category_id, comments, views);

查看索引
在这里插入图片描述
执行之前的explain

explain select id, author_id from article where category_id = 1 and comments > 1 order by views DESC limit 1;

结果如下
在这里插入图片描述
可见type变成了range,这个是可以忍受的。但是extra里使用Using filesort仍是无法接受的。

但是我们修改查询语句,把comments > 1改为comments = 1

explain select id, author_id from article where category_id = 1 and comments = 1 order by views DESC limit 1;

结果如下
在这里插入图片描述
会发现,range进一步优化成为了ref,Extra中的Using filesort也不见了。不过这条sql就违背了需求。(不过也可以得出结论,一般sql以等于为主,可以达到更好的优化。)

根据BTree索引的工作原理,先排序category_id,如果遇到相同的category_id则再排序comments,如果遇到相同的comments再排序views。
当comments字段在联合索引里处于中间位置时,因comments > 1条件是一个范围值(所谓range),MySQL无法利用索引再对后面的views部分进行检索,即range类型查询字段后面的索引无效,这也是为什么还有Using filesort的原因。

3、进一步优化查询

删除之前的索引,创建新的索引

drop index idx_article_ccv on article;
create index idx_article_cv on article(category_id, views);
show index from article;

查看新创建索引
在这里插入图片描述
执行

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也消失了,结果非常理想。

二、双表

创建数据表

create table if not exists class (
    id int(10) unsigned not null auto_increment,
    card int(10) unsigned not null,
    primary key (id)
);
create table if not exists book (
    book_id int(10) unsigned not null auto_increment,
    card int(10) unsigned not null,
    primary key (book_id)
);
# 执行20次
insert into class(card) values (floor(1 + (rand() * 20)));
# 执行20次
insert into class(book) values (floor(1 + (rand() * 20)));

1、左连接(left join)
1)初步查询

执行,class相当于book的左表。

explain select * from class left join book on class.card = book.card;

结果如下
在这里插入图片描述
看到了type中的all就需要优化了。

1)优化查询

删除book表索引

drop index Y on book;

给class的card添加索引(给左表添加索引)

alter table class add index Y (card);

执行

explain select * from class left join book on class.card = book.card;

结果如下
在这里插入图片描述
可见第一行type变成了index。

2)进一步优化查询

给book的card添加索引(给右表添加索引)

alter table book add index Y (card);

执行

explain select * from class left join book on class.card = book.card;

结果如下
在这里插入图片描述
可以看见第二行的type变为了ref,rows、Extra也被优化了,整体优化比较明显。

这个是由左连接特性决定的(左表全都有),left join条件用于确定如何从右表搜索行,左表一定是都有的。所以右表是关键点,一定要建立索引。

3)细节

对于给class的card添加索引优化不如给book的card添加索引优化效果明显。如何不更改索引,就能达到右表优化呢?
其实查询sql语句中两表位置互换下即可。

explain select * from book left join class on class.card = book.card;

结果如下
在这里插入图片描述
同样可以达到效果。

2、右连接(right join)

思路和左连接一样
right join条件用于确定如何从左表查询,右表一定都有,所以左表是我们的关键点,一定要建立索引。

三、三表

新增新表

create table if not exists phone (
    phone_id int(10) unsigned not null auto_increment,
    card int(10) unsigned not null,
    primary key (phone_id)
);
# 执行20次
insert into phone(card) values (floor(1 + (rand() * 20)));

执行

explain select * from class left join book on class.card = book.card left join phone on book.card = phone.card;

结果如下
在这里插入图片描述
给phone和book创建索引

alter table phone add index Z (card);
alter table book add index Y (card);

执行

explain select * from class left join book on class.card = book.card left join phone on book.card = phone.card;

结果如下
在这里插入图片描述
后两行的type都是ref且总rows优化很好,效果不错。同样的道理,这里的phone相当于book的右表,而book相当于class的右表。

四、结论

Join语句优化
1)尽可能减少Join语句中的嵌套循环总次数,永远用小结果集驱动大的结果集(例如书的类别是小结果集,书的名称是大结果集)。
2)优先优化嵌套循环的内层循环。
3)保证Join语句中被驱动表上Join条件字段已经被索引。
4)当无法保证被驱动表的Join条件字段被索引且内存资源充足的前提下,不要太吝啬JoinBuffer的设置。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值