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的設置。

發佈了71 篇原創文章 · 獲贊 37 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章