MySQL優化--關聯查詢、子查詢、排序分組的優化

一、關聯查詢的優化

在做join的時候,原理爲驅動表(主表)做全表掃描,對子表(被驅動表)可以利用索引進行優化,而驅動表的全表掃描是必須存在的。

建表sql

 
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` (
`bookid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`card` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`bookid`)
);

當有一條查詢SQL爲:

SELECT * FROM class LEFT JOIN book ON class.card = book.card;

explain一下,發現兩張表都是ALL全表掃描。我們嘗試進行增加索引來進行優化。因爲驅動表必須是進行全表掃描,所以我們對被驅動表的連接條件進行建立索引,發現被驅動表的查詢type變爲了ref,且rows也明顯優化。

總結:1.保證被驅動表的join字段已經被索引

2.left join  或 right join時,將小表作爲驅動表(因爲要必須要進行全表掃描),將數據量大的表作爲被驅動表。

3.inner join時,MySQL會自動把小結果集的表作爲驅動表,這不需要我們關心,但高版本MySQL(5.8)後,inner join的優化策略改變了,改變爲當大表作爲驅動表時,對大表建立 auto_key 索引。這不需要過多關注。

4.子查詢儘量不要放在被驅動表,因爲查詢出的衍生表無法建立索引。

5.能用連接查詢,就不要用子查詢。

二、子查詢優化

根據業務需求,當在子查詢中出現 not in 字段時,完全可以用連接查詢代替

A.id not in (select B.id)

可以替換爲

A left join B on A.id = B.id where B.id = null

三、排序和分組優化

衆所周知,在order by 和group by 子句中用到的字段加索引會大大提高查詢效率,並可以有效避免 file sorted這種嚴重影響效率的情況。

首先建立一個索引

 create index idx_age_deptid_name on emp (age,deptid,name)

在Order by 子句的優化:

1.無過濾,不索引

#無法用到索引
explain  select SQL_NO_CACHE * from emp order by age,deptid; 
 #使用到了索引
explain  select SQL_NO_CACHE * from emp order by age,deptid limit 10; 

在Oder by子句中,如果想用到索引,必須要有限制條件,如where 或limit ,不然無法用到索引

2.順序錯,必排序(file sorted)

3、  explain  select * from emp where age=45 order by deptid;
 
 
4、explain  select * from emp where age=45 order by   deptid,name; 
 
5、explain  select * from emp where age=45 order by  deptid,empno;
 
6、explain  select * from emp where age=45 order by  name,deptid;
 
7、 explain select * from emp where deptid=45 order by age;

MySQL的 Optimizer會自動優化where中的查詢順序,但不會對order by子句中的字段順序進行優化,所以只有當oder by 後的字段順序與索引字段順序一致時 纔可以用到索引

3.方向反,必排序

#可以用到索引
explain select * from emp where age=45 order by  deptid desc, name desc ;
#沒有用到索引
explain select * from emp where age=45 order by  deptid asc, name desc ;

order by 後的字段排序必須一致,如不同,則索引失效。

4.我們都知道sql的執行順序爲先執行where 再執行 order by 或 group by,如果where中有範圍查詢怎麼辦?範圍查詢的字段右邊的索引全部失效,這時就要綜合考慮。

結論: 當範圍條件和group by 或者 order by  的字段出現二選一時 ,優先觀察條件字段的過濾數量,如果過濾的數據足夠多,而需要排序的數據並不多時,優先把索引放在範圍字段上。反之,亦然。

 

group by 子句的優化與order by基本一致,唯一的區別就是group by 使用時,即使沒有過濾條件,也可以直接使用索引。

 

四、覆蓋索引

簡單說就是,select 到 from 之間查詢的列 <=使用的索引列+主鍵,這就是爲什麼在查詢中不建議使用 * 的主要原因。

覆蓋索引不會進行大級別的優化,但在沒有辦法的時候,還是可以試一試,

<>無法用到索引,但可以通過覆蓋索引去利用上索引。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章