SQL語句在不一樣的人手中會寫出不一樣的語句形式,好比常常遇到的SQL慢查詢,這時候每每須要針對SQL進行優化。
而Mysql中爲保證SQL語句可以高效的運行,提供了一個Explain的命令,用來對SQL語句進行語義分析,供開發者來針對SQL進行優化。
sql
爲了方便整個流程的執行,首先建立好測試數據。數據庫
SQL中的執行涉及到單表與多表的聯合執行,本次建立兩張表用來模擬該狀況,更多的多表聯合執行與兩張表執行計劃是同樣的。緩存
CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用戶名', `sex` tinyint(4) NOT NULL DEFAULT '1' COMMENT '性別', `phone` varchar(11) NOT NULL COMMENT '手機號', `desc` varchar(200) NOT NULL DEFAULT '' COMMENT '介紹', primary key (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '用戶表'; CREATE TABLE `order`( `id` int(11) NOT NULL AUTO_INCREMENT, `phone` varchar(11) NOT NULL COMMENT '手機號', `name` varchar(20) NOT NULL COMMENT '用戶名', primary key (`id`) ) ENGINE =InnoDB default CHARSET=utf8 COMMENT '訂單';
爲了方便本次沒有使用SQL語句,而是使用存儲過程建立數據,簡單快速也方便。性能優化
# 建立 存儲過程 create procedure insert_user_data() begin declare i int ; declare name varchar(20); declare phone_num varchar(11); set @SURNAME = '王李張劉陳楊黃趙吳周徐孫馬朱胡郭何高林羅鄭梁謝宋唐位許韓馮鄧曹彭曾蕭田董潘袁於蔣蔡餘杜葉程蘇魏呂丁任沈姚盧姜崔鍾譚陸汪範金石廖賈夏韋傅方白鄒孟熊秦邱江尹薛閻段雷侯龍史陶黎賀顧毛郝龔邵萬錢嚴覃武戴莫孔向湯'; set @NAME = '丹舉義之樂書乾雲亦從代以偉佑俊修健傲兒元光蘭冬冰冷凌凝凡凱初力勤千卉半華南博又友同向君聽和哲嘉國堅城夏夜天奇奧如妙子存季孤宇安宛宸寒尋爾堯山嵐峻巧平幼康建開弘強彤彥彬彭心憶志念懷憐恨惜慕成擎敏文新旋旭昊明易昕映春昱晉曉晗晟景晴智曼朋朗傑鬆楓柏柔柳格桃夢楷槐正水沛波澤潔洋濟浦浩海濤潤涵淵源溥濮瀚靈燦炎煙燁然煊煜熙熠玉珊珍理琪琴瑜瑞瑤瑾璞癡皓盼真睿碧磊祥祺秉程立竹笑紫紹經綠羣翠翰致航良芙芷蒼苑若茂榮蓮菡菱萱蓉藍蕊蕾薇蝶覓訪誠語谷豪賦超越軒輝達遠邃醉金鑫錦問雁雅雨雪霖霜露青靖靜風飛香馳騫高鴻鵬鶴黎'; set i =1; while i < 100000 do SET phone_num = concat('1', substring(cast(3 + (rand() * 10) % 7 AS char(50)), 1, 1), right(left(trim(cast(rand() AS char(50))), 11), 9)); set name = concat(substr(@surname,floor(rand()*length(@surname)/3+1),1), substr(@NAME,floor(rand()*length(@NAME)/3+1),1), substr(@NAME,floor(rand()*length(@NAME)/3+1),1)); insert into users(create_time,name, sex,phone ,`desc`) values(now(),name,rand()*1,phone_num ,'test'); insert into `order`(phone,name) values(phone_num,name); set i=i+1; end while; end # 執行存儲過程 call insert_user_data(); # 刪除存儲過程 drop procedure if exists insert_user_data ;
建立存儲過程後,有須要修改就直接使用刪除存儲過程,再從新建立便可。服務器
explain的執行命令explain select * from users where id =1 \G;
展現以下:微信
*************************** 1. row *************************** id: 1 select_type: SIMPLE table: users partitions: NULL type: const possible_keys: PRIMARY key: PRIMARY key_len: 4 ref: const rows: 1 filtered: 100.00 Extra: NULL 1 row in set, 1 warning (0.00 sec)
一共12個字段,各個字段的含義以下:oop
有些字段有更多的類型,如下是詳細講解。
用來表示每一個查詢類型,經常使用類型以下:
select * from users where id =1
explain select * from users where phone=(select phone from order where id = 10);
explain select * from users where id = 10 union select * from users where id = 20;
explain select * from users where phone=(select phone from order where id = users.id ) and id =10;
。 在這裏面最多見的類型就屬於SIMPLE類型,咱們常用的多表查詢也是SIMPLE類型。例如explain select * from users left join order o on users.phone = o.phone where users.id =10
type字段幫助咱們來定位查詢是否高效,是全表掃描仍是索引掃描。
不一樣的type,表明的性能不同,順序以下:
ALL < index < range ~ index_merge < ref < eq_ref < const < system
經常使用類型以下:
explain select * from users;
,能夠看到全表掃描掃了200多萬行的數據。 explain select id from users;
查詢語句中id是主鍵索引,則只查詢的是索引數據.explain select phone from users where id > 10 and id < 20 ;
SQL語句中使用>和<來限定where條件使用的仍是range,$\color{red}{當語句中的字段不是索引時,則不是使用的range}$ explain select * from order where phone ='16485461071'
explain select * from users, order where users.id=order.id
explain select * from order where id =10;
查詢中所須要掃描的行數,咱們使用各類索引,優化都是爲了減小掃描的行數。
表示在查詢時,表的鏈接匹配條件,能夠是常量,也能夠是查詢的列explain select * from users, order where users.id=order.id;
extra 表示更多的sql查詢信息,extra是Mysql查詢計劃中查詢信息重要補充。extra的類型以下:
明白SQL的查詢計劃,當再寫SQL時,多多使用explain語句來看下SQL的查詢計劃是怎樣的,心中對SQL的執行有大概的瞭解,方能得心運手。
本文中用到的SQL語句上傳到github中須要的自取
·END·
路雖遠,行則必至
本文原發於 同名微信公衆號「胖琪的升級之路」,回覆「1024」你懂得,給個讚唄。
微信ID:YoungRUIQ