一、關聯查詢的優化
在做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 之間查詢的列 <=使用的索引列+主鍵,這就是爲什麼在查詢中不建議使用 * 的主要原因。
覆蓋索引不會進行大級別的優化,但在沒有辦法的時候,還是可以試一試,
<>無法用到索引,但可以通過覆蓋索引去利用上索引。