未找到要求的 from 关键字_性能优化|这恐怕是解释Explain关键字最全的一篇文章
本次測試使用的數據庫版本為5.7 初始化sql語句:
CREATE TABLE `film` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(10) DEFAULT NULL,PRIMARY KEY (`id`),KEY `idx_name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;CREATE TABLE `actor` (`id` int(11) NOT NULL,`name` varchar(45) DEFAULT NULL,`update_time` datetime DEFAULT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO `xnyh`.`actor`(`id`, `name`, `update_time`) VALUES (1, 'a', '2017-12-02 15:27:18'); INSERT INTO `xnyh`.`actor`(`id`, `name`, `update_time`) VALUES (2, 'b', '2017-12-22 15:27:18'); INSERT INTO `xnyh`.`actor`(`id`, `name`, `update_time`) VALUES (3, 'c', '2017-12-22 15:27:18');INSERT INTO `xnyh`.`film`(`id`, `name`) VALUES (2, 'film 2'); INSERT INTO `xnyh`.`film`(`id`, `name`) VALUES (3, 'film0'); INSERT INTO `xnyh`.`film`(`id`, `name`) VALUES (1, 'film1');CREATE TABLE `film_actor` (`id` INT ( 11 ) NOT NULL,`film_id` INT ( 11 ) NOT NULL,`actor_id` INT ( 11 ) NOT NULL,`remark` VARCHAR ( 255 ) DEFAULT NULL,PRIMARY KEY ( `id` ),KEY `idx_film_actor_id` (`film_id`,`actor_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO `film_actor` (`id`, `film_id`, `actor_id`) VALUES (1,1,1), (2,1,2),(3,2,1);先執行exlpain語句,EXPLAIN SELECT * from db,執行結果如下:
我們接下來對這12個字段依次進行解釋
ID列
id列的值是代表了select語句執行順序,是和select相關聯的;id列的值大會優先執行,如果id列為空最后執行,id列相同,則從上到下依次執行。
select_type列
代表查詢的類型,有如下幾個值:
simple:
不包含子查詢和join關鍵字 explain select * from film where id = 2;
primary:
復雜查詢最外層select語句或者union語句中最左邊的select explain select *,(select id from actor where id=1) from film
最外層查的是film表的,所以film對應的查詢類型就是primary;
subquery:
僅限在from前面的select語句,不包括select后面的語句 explain select *,(select id from actor where id=1) from film
derived:
衍生表,如果from子句后面包含select語句,則會產生這種類型,它會把中間結果存放在臨時表中,但是在5.7中需要使用set session optimizer_switch='derived_merge=off';關閉mysql對衍生表的合并優化,我們先看下不關閉之前,我們執行如下sql的情況: explain select (select 1 from actor where id = 1) from (select * from film where id = 1) der;
發現查詢類型沒有derived,我們關閉優化看下set session optimizer_switch='derived_merge=off'
發現出現了derived查詢了,
union:
在 union 中的第二個和隨后的 select explain select 1 union select 2 UNION select 3
table列
table列代表當前select語句正在查詢哪張表。 EXPLAIN SELECT id from actor UNION select id from film
優先執行的是union后面的查詢語句當前訪問的是film表,接著執行union左邊查詢語句,當前查詢的是actor表,最后查詢的是依賴1和2的查詢結果,所以使用<union1,2>來代替。
type列
type列的值分別為: NULL>system > const > eq_ref > ref > range > index > ALL; 執行效率依次遞減。
NULL:
代表查詢在mysql能夠在優化階段分解查詢語句的時候直接能完成,不需要查詢表和索引,例如獲取逐漸最大列或最小列: EXPLAIN select min(id),max(id) from film
const:
當where后面是一個主鍵或者唯一索引 與一個常量精確比較時,mysql會把查詢優化為常量查詢,執行如下sql: explain select * from film where id = 2
我們可以看下mysql內部進行了如何優化: explain EXTENDED select * from film where id = 2; show WARNINGS;
可以看出mysql直接將其轉換為常量進行查詢
system:
如果要達到sysytem級別,那么它必須要達到以下幾個條件:
1.是系統表或者是臨時表 2.表中有且只有一條記錄
- 我在mysql庫中找到了proxies_priv表,我們看執行如下sql: explain select * from proxies_priv
可以看出已經到了system級別;
- 我們再看一種情況:派生表(臨時表) explain extended select * from (select * from film where id = 1) tmp;
可以看到查詢類型為PRIMARY已經達到了system級別,它是從派生表(臨時表)中查詢,并且派生表中只有一條記錄,也能夠達到system級別。
eq_ref:
主鍵或者唯一索引與其它表或字段進行關聯查詢,最多只會返回一條記錄,如下代碼: explain select * from film_actor left join film on film_actor.film_id = film.id;
可以看出訪問film表的時候,type達到了eq_ref級別,因為id字段在film表中是唯一的,所以查詢film表的時候按照id查詢只會有一條記錄與其關聯;
ref:
相對于eq_ref,ref只需要要求是普通索引或者聯合索引的前綴匹配
- 普通索引查詢explain select * from film where name = 'film1';
- 聯合索引前綴匹配 explain select film_id from film left join film_actor on film.id = film_actor.film_id;
range:
范圍索引,通常為in、> < >= 這樣的比較符,會達到range級別 explain select * from actor where id > 1;
index
掃描全表索引:所查詢的列都創建了索引,但是沒有按照索引字段過濾(除了讓索引失效的操作除外) explain select * from film
all
掃描全表,通常情況下,是沒有創建索引,需要增加索引優化 explain select * from actor;
possible_keys
這一列顯示查詢可能使用哪些索引來查找。 explain 時可能出現 possible_keys 有列,而 key 顯示 NULL 的情況,這種情況是因為表中 數據不多,mysql認為索引對此查詢幫助不大,選擇了全表查詢。 如果該列是NULL,則沒有相關的索引。在這種情況下,可以通過檢查 where 子句看是否可 以創造一個適當的索引來提高查詢性能,然后用 explain 查看效果。
key
這一列顯示mysql實際采用哪個索引來優化對該表的訪問。 如果沒有使用索引,則該列是 NULL。如果想強制mysql使用或忽視possible_keys列中的索 引,在查詢中使用 force index、ignore index。
key_len
該列記錄了使用索引的長度,一般用來判斷聯合索引是否全部生效的作用,該值是根據不同數據類型進行計算的。
key_len計算規則如下:
- 字符串
- char(n):n字節長度
- varchar(n):2字節存儲字符串長度,如果是utf-8,則長度 3n + 2
- 數值類型
- tinyint:1字節
- smallint:2字節
- int:4字節
- bigint:8字節
- 時間類型
- date:3字節
- timestamp:4字節
- datetime:8字節
如果字段允許為 NULL,需要1字節記錄是否為 NULL 索引最大長度是768字節,當字符串過長時,mysql會做一個類似左前綴索引的處理,將前半 部分的字符提取出來做索引。
在創建表film_actor的時候我們已經創建了聯合索引
KEY `idx_film_actor_id` (`film_id`,`actor_id`)我們利用這個聯合索引進行計算
- 只使用聯合索引的第一個字段: explain select * from film_actor where film_id = 2;
可以看到key_len是4,我們是根據聯合索引字段的第一個字段進行過濾的,我們看下film_id字段的類型的int類型,結合上面的計算方式,file_id不能為NULL,那么key_len就是4;
- 使用聯合索引的兩個字段: explain select * from film_actor where film_id = 2 and actor_id = 3
發現結果為8,這個因為這兩個字段都是int類型,并且都不為NUll,那么加起來索引長度就是8,那就說明這個索引完全生效了。
ref
這一列顯示了在key列記錄的索引中,表查找值所用到的列或常量,常見的有:const(常 量),字段名(例:film.id)
rows
這一列是mysql估計要讀取并檢測的行數,注意這個不是結果集里的行數。
Extra列
這個展示索引的額外信息,主要字段信息如下:
- Using index 查詢的字段被索引覆蓋explain select film_id from film_actor
- using where where 后面的字段沒有使用被創建索引,優化方式,創建索引。 explain select film_id from film_actor where remark = '描述';
- using index condition 查詢的語句中,where條件中是一個前導列的范圍; explain select * from film_actor where film_id = 1 and actor_id >3;
- Using temporary 創建臨時表,mysql查詢過程中需要創建臨時表來輔助查詢,像這種情況是需要優化的。 explain select distinct name from actor;
通過給去重的字段添加索引,可達到優化的效果 CREATE index idx_name on actor(name)
方便后續測試,需要刪除剛創建的索引:DROP INDEX idx_name on actor
- Using filesort 數據排序的時候沒有通過索引排序,當數據量小時通過內存排序,大的時候在磁盤中進行排序,需要進行索引優化,通常是排序字段沒有創建索引。 explain select * from actor order by name;
下面的排序字段創建了索引,所以是在索引內進行排序 explain select * from film order by name;
- Select tables optimized away 對某個創建了索引的字段查詢使用了聚合函數 explain select max(id) from actor
總結
以上是生活随笔為你收集整理的未找到要求的 from 关键字_性能优化|这恐怕是解释Explain关键字最全的一篇文章的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: echarts 雷达图_如何把Echar
- 下一篇: python统计字典里面value出现的