MySql查詢過程:
1、通過查看執行計划
在執行語句前加上 explain
點擊查看代碼
mysql> explain select * from testmvcc;
+----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------+
| 1 | SIMPLE | testmvcc | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | NULL |
+----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.01 sec)
1、執行計划中包含的信息
Column | Meaning |
---|---|
id | The SELECT identifier |
select_type | The SELECT type |
table | The table for the output row |
partitions | The matching partitions |
type | The join type |
possible_keys | The possible indexes to choose |
key | The index actually chosen |
key_len | The length of the chosen key |
ref | The columns compared to the index |
rows | Estimate of rows to be examined |
filtered | Percentage of rows filtered by table condition |
extra | Additional information |
id
select查詢的序列號,包含一組數字,表示查詢中執行select子句或者操作表的順序
id號分為三種情況:
1、如果id相同,那么執行順序從上到下
explain select * from emp e join dept d on e.deptno = d.deptno join salgrade sg on e.sal between sg.losal and sg.hisal;
2、如果id不同,如果是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
explain select * from emp e where e.deptno in (select d.deptno from dept d where d.dname = 'SALES');
3、id相同和不同的,同時存在:相同的可以認為是一組,從上往下順序執行,在所有組中,id值越大,優先級越高,越先執行
explain select * from emp e join dept d on e.deptno = d.deptno join salgrade sg on e.sal between sg.losal and sg.hisal where e.deptno in (select d.deptno from dept d where d.dname = 'SALES');
select_type
主要用來分辨查詢的類型,是普通查詢還是聯合查詢還是子查詢
select_type Value |
Meaning |
---|---|
SIMPLE | 簡單的SELECT(不使用UNION或子查詢) |
PRIMARY | 外層的選擇 |
UNION | UNION中的第二個或后面的SELECT語句 |
DEPENDENT UNION | UNION中的第二個或后面的SELECT語句,取決於外部查詢 |
UNION RESULT | UNION的結果。 |
SUBQUERY | 首先在子查詢中選擇 |
DEPENDENT SUBQUERY | 首先在子查詢中選擇,依賴於外部查詢 |
DERIVED | 派生表 |
UNCACHEABLE SUBQUERY | 無法緩存其結果的子查詢,且必須為外部查詢的每一行重新求值 |
UNCACHEABLE UNION | 屬於非緩存子查詢的UNION中的第二個或后面的選擇(參見非緩存子查詢) |
--sample:簡單的查詢,不包含子查詢和union
explain select * from emp;
--primary:查詢中若包含任何復雜的子查詢,最外層查詢則被標記為Primary
explain select staname,ename supname from (select ename staname,mgr from emp) t join emp on t.mgr=emp.empno ;
--union:若第二個select出現在union之后,則被標記為union
explain select * from emp where deptno = 10 union select * from emp where sal >2000;
--dependent union:跟union類似,此處的depentent表示union或union all聯合而成的結果會受外部表影響
explain select * from emp e where e.empno in ( select empno from emp where deptno = 10 union select empno from emp where sal >2000)
--union result:從union表獲取結果的select
explain select * from emp where deptno = 10 union select * from emp where sal >2000;
--subquery:在select或者where列表中包含子查詢
explain select * from emp where sal > (select avg(sal) from emp) ;
--dependent subquery:subquery的子查詢要受到外部表查詢的影響
explain select * from emp e where e.deptno in (select distinct deptno from dept);
--DERIVED: from子句中出現的子查詢,也叫做派生類,
explain select staname,ename supname from (select ename staname,mgr from emp) t join emp on t.mgr=emp.empno ;
--UNCACHEABLE SUBQUERY:表示使用子查詢的結果不能被緩存
explain select * from emp where empno = (select empno from emp where deptno=@@sort_buffer_size);
--uncacheable union:表示union的查詢結果不能被緩存:sql語句未驗證
table
對應行正在訪問哪一個表,表名或者別名,可能是臨時表或者union合並結果集
1、如果是具體的表名,則表明從實際的物理表中獲取數據,當然也可以是表的別名
2、表名是derivedN的形式,表示使用了id為N的查詢產生的衍生表
3、當有union result的時候,表名是union n1,n2等的形式,n1,n2表示參與union的id
type
type顯示的是訪問類型,訪問類型表示我是以何種方式去訪問我們的數據,最容易想的是全表掃描,直接暴力的遍歷一張表去尋找需要的數據,效率非常低下,訪問的類型有很多,效率從最好到最壞依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般情況下,得保證查詢至少達到range級別,最好能達到ref
--all:全表掃描,一般情況下出現這樣的sql語句而且數據量比較大的話那么就需要進行優化。
explain select * from emp;
--index:全索引掃描這個比all的效率要好,主要有兩種情況,一種是當前的查詢時覆蓋索引,即我們需要的數據在索引中就可以索取,或者是使用了索引進行排序,這樣就避免數據的重排序
explain select empno from emp;
--range:表示利用索引查詢的時候限制了范圍,在指定范圍內進行查詢,這樣避免了index的全索引掃描,適用的操作符: =, <>, >, >=, <, <=, IS NULL, BETWEEN, LIKE, or IN()
explain select * from emp where empno between 7000 and 7500;
--index_subquery:利用索引來關聯子查詢,不再掃描全表
explain select * from emp where emp.job in (select job from t_job);
--unique_subquery:該連接類型類似與index_subquery,使用的是唯一索引
explain select * from emp e where e.deptno in (select distinct deptno from dept);
--index_merge:在查詢過程中需要多個索引組合使用,沒有模擬出來
--ref_or_null:對於某個字段即需要關聯條件,也需要null值的情況下,查詢優化器會選擇這種訪問方式
explain select * from emp e where e.mgr is null or e.mgr=7369;
--ref:使用了非唯一性索引進行數據的查找
create index idx_3 on emp(deptno);
explain select * from emp e,dept d where e.deptno =d.deptno;
--eq_ref :使用唯一性索引進行數據查找
explain select * from emp,emp2 where emp.empno = emp2.empno;
--const:這個表至多有一個匹配行,
explain select * from emp where empno = 7369;
--system:表只有一行記錄(等於系統表),這是const類型的特例,平時不會出現
possible_keys
顯示可能應用在這張表中的索引,一個或多個,查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被查詢實際使用
explain select * from emp,dept where emp.deptno = dept.deptno and emp.deptno = 10;
key
實際使用的索引,如果為null,則沒有使用索引,查詢中若使用了覆蓋索引,則該索引和查詢的select字段重疊。
explain select * from emp,dept where emp.deptno = dept.deptno and emp.deptno = 10;
key_len
表示索引中使用的字節數,可以通過key_len計算查詢中使用的索引長度,在不損失精度的情況下長度越短越好。
explain select * from emp,dept where emp.deptno = dept.deptno and emp.deptno = 10;
ref
顯示索引的哪一列被使用了,如果可能的話,是一個常數
explain select * from emp,dept where emp.deptno = dept.deptno and emp.deptno = 10;
rows
根據表的統計信息及索引使用情況,大致估算出找出所需記錄需要讀取的行數,此參數很重要,直接反應的sql找了多少數據,在完成目的的情況下越少越好
explain select * from emp;
extra
包含額外的信息。
--using filesort:說明mysql無法利用索引進行排序,只能利用排序算法進行排序,會消耗額外的位置
explain select * from emp order by sal;
--using temporary:建立臨時表來保存中間結果,查詢完成之后把臨時表刪除
explain select ename,count(*) from emp where deptno = 10 group by ename;
--using index:這個表示當前的查詢時覆蓋索引的,直接從索引中讀取數據,而不用訪問數據表。如果同時出現using where 表名索引被用來執行索引鍵值的查找,如果沒有,表面索引被用來讀取數據,而不是真的查找
explain select deptno,count(*) from emp group by deptno limit 10;
--using where:使用where進行條件過濾
explain select * from t_user where id = 1;
--using join buffer:使用連接緩存,情況沒有模擬出來
--impossible where:where語句的結果總是false
explain select * from emp where empno = 7469;