mysql 部门表_MySQL高级
本文大綱
環境
win10-64
MySQL Community Server 5.7.1
mysqld –version可查看版本
官方文檔
SQL執行順序
手寫順序
我們可以將手寫SQL時遵循的格式歸結如下:
select?distinct????from??join??on?wheregroup?byhavingorder?bylimit?<offset>,<rows>
distinct,用于對查詢出的結果集去重(若查出各列值相同的多條結果則只算一條)
join,關聯表查詢,若將兩個表看成兩個集合,則能有7種不同的查詢效果(將在下節介紹)。
group by,通常與合計函數結合使用,將結果集按一個或多個列值分組后再合計
having,通常與合計函數結合使用,彌補where條件中無法使用函數
order by,按某個標準排序,結合asc/desc實現升序降序
limit,如果跟一個整數n則表示返回前n條結果;如果跟兩個整數m,n則表示返回第m條結果之后的n條結果(不包括第m條結果)
MySQL引擎解析順序
而我們將SQL語句發給MySQL服務時,其解析執行的順序一般是下面這樣:
from????
on
????
?join
????
where
????
group?by
????
having
????
select
????
order?by
????
limit
????offset,rows
了解這個對于后續分析SQL執行計劃提供依據。
七種Join方式
下面我們創建部門表tbl_dept和員工表tbl_emp對上述7種方式進行逐一實現:
部門表:主鍵id、部門名稱deptName,部門樓層locAdd
????->??`id`?INT(11)?NOT?NULL?AUTO_INCREMENT,
????->??`deptName`?VARCHAR(30)?DEFAULT?NULL,
????->??`locAdd`?VARCHAR(40)?DEFAULT?NULL,
????->??PRIMARY?KEY?(`id`)
????->?)?ENGINE=INNODB?AUTO_INCREMENT=1?DEFAULT?CHARSET=utf8;
員工表:主鍵id,姓名name、所屬部門deptId
????->??`id`?INT(11)?NOT?NULL?AUTO_INCREMENT,
????->??`name`?VARCHAR(20)?DEFAULT?NULL,
????->??`deptId`?INT(11)?DEFAULT?NULL,
????->??PRIMARY?KEY?(`id`),
????->??KEY?`fk_dept_id`?(`deptId`)
????->??#CONSTRAINT?`fk_dept_id`?FOREIGN?KEY?(`deptId`)?REFERENCES?`tbl_dept`?(`id`)
????->?)?ENGINE=INNODB?AUTO_INCREMENT=1?DEFAULT?CHARSET=utf8;
插入一些測試數據:
mysql>?INSERT?INTO?tbl_dept(deptName,locAdd)?VALUES('技術部',11);Query?OK,?1?row?affected?(0.07?sec)
mysql>?INSERT?INTO?tbl_dept(deptName,locAdd)?VALUES('美工部',12);
Query?OK,?1?row?affected?(0.08?sec)
mysql>?INSERT?INTO?tbl_dept(deptName,locAdd)?VALUES('總裁辦',13);
Query?OK,?1?row?affected?(0.06?sec)
mysql>?INSERT?INTO?tbl_dept(deptName,locAdd)?VALUES('人力資源',14);
Query?OK,?1?row?affected?(0.11?sec)
mysql>?INSERT?INTO?tbl_dept(deptName,locAdd)?VALUES('后勤組',15);
Query?OK,?1?row?affected?(0.10?sec)
mysql>?insert?into?tbl_emp(name,deptId)?values('jack',1);
Query?OK,?1?row?affected?(0.11?sec)
mysql>?insert?into?tbl_emp(name,deptId)?values('tom',1);
Query?OK,?1?row?affected?(0.08?sec)
mysql>?insert?into?tbl_emp(name,deptId)?values('alice',2);
Query?OK,?1?row?affected?(0.08?sec)
mysql>?insert?into?tbl_emp(name,deptId)?values('john',3);
Query?OK,?1?row?affected?(0.13?sec)
mysql>?insert?into?tbl_emp(name,deptId)?values('faker',4);
Query?OK,?1?row?affected?(0.10?sec)
mysql>?insert?into?tbl_emp(name)?values('mlxg');
Query?OK,?1?row?affected?(0.13?sec)
mysql>?select?*?from?tbl_dept;
+----+----------+--------+
|?id?|?deptName?|?locAdd?|
+----+----------+--------+
|??1?|?技術部???|?11?????|
|??2?|?美工部???|?12?????|
|??3?|?總裁辦???|?13?????|
|??4?|?人力資源?|?14?????|
|??5?|?后勤組???|?15?????|
+----+----------+--------+
5?rows?in?set?(0.00?sec)
mysql>?select?*?from?tbl_emp;
+----+-------+--------+
|?id?|?name??|?deptId?|
+----+-------+--------+
|??1?|?jack??|??????1?|
|??2?|?tom???|??????1?|
|??3?|?alice?|??????2?|
|??4?|?john??|??????3?|
|??5?|?faker?|??????4?|
|??7?|?ning??|???NULL?|
|??8?|?mlxg??|???NULL?|
+----+-------+--------+
7?rows?in?set?(0.00?sec)
兩表的關聯關系如圖所示:
1、左連接(A獨有+AB共有)
查詢所有部門以及各部門的員工數:
mysql>?select?t1.id,t1.deptName,count(t2.name)?as?emps?from?tbl_dept?t1?left?join?tbl_emp?t2?on?t2.deptId=t1.id?group?by?deptName?order?by?id;+----+----------+------+
|?id?|?deptName?|?emps?|
+----+----------+------+
|??1?|?技術部???|????2?|
|??2?|?美工部???|????1?|
|??3?|?總裁辦???|????1?|
|??4?|?人力資源?|????1?|
|??5?|?后勤組???|????0?|
+----+----------+------+
5?rows?in?set?(0.00?sec)
2、右連接(B獨有+AB共有)
查詢所有員工及其所屬部門:
mysql>?select?t2.id,t2.name,t1.deptName?from?tbl_dept?t1?right?join?tbl_emp?t2?on?t2.deptId=t1.id;+----+-------+----------+
|?id?|?name??|?deptName?|
+----+-------+----------+
|??1?|?jack??|?技術部???|
|??2?|?tom???|?技術部???|
|??3?|?alice?|?美工部???|
|??4?|?john??|?總裁辦???|
|??5?|?faker?|?人力資源?|
|??7?|?ning??|?NULL?????|
|??8?|?mlxg??|?NULL?????|
+----+-------+----------+
7?rows?in?set?(0.04?sec)
3、內連接(AB共有)
查詢兩表共有的數據:
mysql>?select?deptName,t2.name?empName?from?tbl_dept?t1?inner?join?tbl_emp?t2?on?t1.id=t2.deptId;+----------+---------+
|?deptName?|?empName?|
+----------+---------+
|?技術部???|?jack????|
|?技術部???|?tom?????|
|?美工部???|?alice???|
|?總裁辦???|?john????|
|?人力資源?|?faker???|
+----------+---------+
4、A獨有
即在(A獨有+AB共有)的基礎之上排除B即可(通過b.id is null即可實現):
mysql>?select?a.deptName,b.name?empName?from?tbl_dept?a?left?join?tbl_emp?b?on?a.id=b.deptId?where?b.id?is?null;+----------+---------+
|?deptName?|?empName?|
+----------+---------+
|?后勤組???|?NULL????|
+----------+---------+
5、B獨有
與(A獨有)同理:
mysql>?select?a.name?empName,b.deptName?from?tbl_emp?a?left?join?tbl_dept?b?on?a.deptId=b.id?where?b.id?is?null;+---------+----------+
|?empName?|?deptName?|
+---------+----------+
|?ning????|?NULL?????|
|?mlxg????|?NULL?????|
+---------+----------+
6、A獨有+B獨有
使用union將(A獨有)和(B獨有)聯合在一起:
mysql>?select?a.deptName,b.name?empName?from?tbl_dept?a?left?join?tbl_emp?b?on?a.id=b.deptId?where?b.id?is?null?union?select?b.deptName,a.name?emptName?from?tbl_emp?a?left?join?tbl_dept?b?on?a.deptId=b.id?where?b.id?is?null;+----------+---------+
|?deptName?|?empName?|
+----------+---------+
|?后勤組???|?NULL????|
|?NULL?????|?ning????|
|?NULL?????|?mlxg????|
+----------+---------+
7、A獨有+AB公共+B獨有
使用union(可去重)聯合(A獨有+AB公共)和(B獨有+AB公共)
mysql>?select?a.deptName,b.name?empName??from?tbl_dept?a?left?join?tbl_emp?b?on?a.id=b.deptId?union?select?a.deptName,b.name?empName?from?tbl_dept?a?right?join?tbl_emp?b?on?a.id=b.deptId;+----------+---------+
|?deptName?|?empName?|
+----------+---------+
|?技術部???|?jack????|
|?技術部???|?tom?????|
|?美工部???|?alice???|
|?總裁辦???|?john????|
|?人力資源?|?faker???|
|?后勤組???|?NULL????|
|?NULL?????|?ning????|
|?NULL?????|?mlxg????|
+----------+---------+
索引與數據處理
什么是索引?
索引是一種數據結構,在插入一條記錄時,它從記錄中提取(建立了索引的字段的)字段值作為該數據結構的元素,該數據結構中的元素被有序組織,因此在建立了索引的字段上搜索記錄時能夠借助二分查找提高搜索效率;此外每個元素還有一個指向它所屬記錄(數據庫表記錄一般保存在磁盤上)的指針,因此索引與數據庫表的關系可類比于字典中目錄與正文的關系,且目錄的篇幅(索引所占的存儲空間存儲空間)很小。
數據庫中,常用的索引數據結構是BTree(也稱B-Tree,即Balance Tree,多路平衡查找樹。Binary Search Tree平衡搜索二叉樹是其中的一個特例)。
建立索引之后為什么快?
索引是大文本數據的摘要,數據體積小,且能二分查找。這樣我們在根據建立了索引的字段搜索時:其一,由表數據變為了索引數據(要查找的數據量顯著減小);其二,索引數據是有序組織的,搜索時間復雜度由線性的O(N)變成了O(logN)(這是很可觀的,意味著線性的2^32次操作被優化成了32次操作)。
MySQL常用索引類型
主鍵索引(primary key),只能作用于一個字段(列),字段值不能為null且不能重復。
唯一索引(unique key),只能作用于一個字段,字段值可以為null但不能重復
普通索引(key),可以作用于一個或多個字段,對字段值沒有限制。為一個字段建立索引時稱為單值索引,為多個字段同時建立索引時稱為復合索引(提取多個字段值組合而成)。
測試唯一索引的不可重復性和可為null:
mysql>?create?table?`student`?(????->?`id`?int(10)?not?null?auto_increment,
????->?`stuId`?int(32)?default?null,
????->?`name`?varchar(100)?default?null,
????->?primary?key(`id`),
????->?unique?key(`stuId`)
????->?)?engine=innodb?auto_increment=1?default?charset=utf8;
mysql>?insert?into?student(stuId,name)?values('123456789','jack');
Query?OK,?1?row?affected?(0.10?sec)
mysql>?insert?into?student(stuId,name)?values('123456789','tom');
ERROR?1062?(23000):?Duplicate?entry?'123456789'?for?key?'stuId'
mysql>?insert?into?student(stuId,name)?values(null,'tom');
Query?OK,?1?row?affected?(0.11?sec)
索引管理
創建索引
創建表(DDL)時創建索引
mysql>?create?table?`student`?(????->?`id`?int(10)?not?null?auto_increment,
????->?`stuId`?int(32)?default?null,
????->?`name`?varchar(100)?default?null,
????->?primary?key(`id`),
????->?unique?key(`stuId`)
????->?)?engine=innodb?auto_increment=1?default?charset=utf8;
創建索引語句:create [unique] index on (,...)
mysql>?create?index?idx_name?on?student(name);Query?OK,?0?rows?affected?(0.44?sec)
Records:?0??Duplicates:?0??Warnings:?0
更改表結構語句:alter table add [unique] index on (,....)
mysql>?drop?index?idx_name?on?student;Query?OK,?0?rows?affected?(0.27?sec)
Records:?0??Duplicates:?0??Warnings:?0
mysql>?alter?table?student?add?index?idx_name(name);
Query?OK,?0?rows?affected?(0.32?sec)
Records:?0??Duplicates:?0??Warnings:?0
刪除索引
drop index on
查看索引
SHOW INDEX FROM
SQL執行計劃——Explain
使用EXPLAIN關鍵字可以模擬優化器執行SQL查詢語句,從而知道MySQL是如何處理你的SQL語句的。分析你的查詢語句或是表結構的性能瓶頸。
能干嘛
通過EXPLAIN分析某條SQL語句執行時的如下特征:
表的讀取順序(涉及到多張表時)
數據讀取操作的操作類型
哪些索引可以使用
哪些索引被實際使用
表之間的引用
每張表有多少行被優化器查詢
怎么玩
格式為:explain :
表頭解析
id
select查詢的序列號,包含一組數字,表示查詢中執行select子句或操作表的順序。根據id是否相同可以分為下列三種情況:
所有表項的id相同,如:
則上表中的3個表項按照從上到下的順序執行,如讀表順序為t1,t3,t2。由第一節提到的SQL解析順序也可驗證,首先from t1,t2,t3表明此次查詢設計到的表,由于沒有join,接著解析where時開始讀表,值得注意的是并不是按照where書寫的順序,而是逆序,即先解析t1.other_column=''于是讀表t1,然后t1.id=t3.id讀表t3,最后t1.id=t2.id讀表t2。解析順序如下:
????t1,t2,t3
where
????t1.other_column='',?t1.id=t3.id,?t1.id=t2.id
select
????t2.*
所有表項的id不同:嵌套查詢,id的序號會遞增,id值越大優先級越高,越先被執行。如:
對于多層嵌套的查詢,執行順序由內而外。解析順序:
????t2
where
????t2.id=
????from
????????t1
????where
????????t1.id=
????????from?
????????????t3
????????where
????????????t3.other_column=''
????????select
????????????t3.id
????select?
????????t1.id
select?
????t2.*
由第12,8,4行可知查表順序為t3,t1,t2。
有的表項id相同,有的則不同。id相同的表項遵循結論1,不同的則遵循結論2
解析順序:
????(
????from
????????t3
????where
????????t3.other_column=''
????select
????????t3.id
?????)?s1,?t2????#s1是衍生表
where
????s1.id=t2.id
select
????t2.*
由第6,11兩行可以看出讀表順序為t3,s1,t2
select_type
該列常出現的值如下:
SIMPLE,表示此SQL是簡單的select查詢,查詢中不包含子查詢或者union
PRIMARY,查詢中若包含任何復雜的子部分,最外層查詢被標記為PRIMARY
SUBQUERY,在select或where列表中包含的子查詢
DERIVED,在from子句中的子查詢被標記為DERIVED(衍生)。MySQL會遞歸執行這些子查詢, 把結果放在臨時表里
UNION,union右側的select
UNION RESULT,union的結果
table
表名,表示該表項是關于哪張表的,也可以是如形式:
,表示該表是表項id為N的衍生表
,表示該表是表項id為M和N兩者union之后的結果
partition
如果啟用了表分區策略,則該字段顯示可能匹配查詢的記錄所在的分區
type
type顯示的是訪問類型,是較為重要的一個指標,結果值從最好到最壞依次是:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL 。
system,表只有一行記錄(等于系統表),這是const類型的特列,平時不會出現,這個也可以忽略不計
const,表示通過索引一次就找到了,const用于比較primary key或者unique key。因為只匹配一行數據,所以很快。若將主鍵置于where列表中,MySQL就能將該查詢轉換為一個常量
+----+-----------+------+
|?id?|?stuId?????|?name?|
+----+-----------+------+
|??1?|?123456789?|?jack?|
|??3?|??????NULL?|?tom??|
+----+-----------+------+
eq_ref,唯一性索引掃描,對于每個索引鍵,表中只有一條記錄與之匹配。常見于主鍵或唯一索引掃描
對于b中的每一條數據,從a的主鍵索引中查找id和其相等的
ref,非唯一性索引掃描,返回匹配某個單獨值的所有行。本質上也是一種索引訪問,它返回所有匹配某個單獨值的行,然而,它可能會找到多個符合條件的行,所以他應該屬于查找和掃描的混合體。(查找是基于有序性的能利用二分,而掃描則是線性的)
- mysql>?create?table?`person`?(
????->??`id`?int(32)?not?null?auto_increment,
????->??`firstName`?varchar(30)?default?null,
????->??`lastName`?varchar(30)?default?null,
????->??primary?key(`id`),
????->??index?idx_name?(firstName,lastName)
????->?)?engine=innodb?auto_increment=1?default?charset=utf8;
查詢姓張的人:
range,根據索引的有序性檢索特定范圍內的行,通常出現在between、、in等范圍檢索中
index,在索引中掃描,只需讀取索引數據。
由于復合索引idx_name是基于(firstName,lastName)的,這種索引只能保證在整體上是按定義時的第一列(即firstName)有序的,當firstName相同時,再按lastName排序,如果不只兩列則以此類推。也就是說在根據lastName查找時是無法利用二分的,只能做全索引掃描。
all,全表掃描,需要從磁盤上讀取表數據。
備注:一般來說,得保證查詢至少達到range級別,最好能達到ref。
possible_keys
MySQL可以利用以快速檢索行的索引。
key
MySQL執行時實際使用的索引。
key_len
表示索引中每個元素最大字節數,可通過該列計算查詢中使用的索引的長度(如何計算稍后詳細結束)。
在不損失精確性的情況下,長度越短越好。
key_len顯示的值為索引字段的最大可能長度,并非實際使用長度,即key_len是根據表定義計算而得,不是通過表內檢索出的。
如何計算?首先我們要了解MySQL各數據類型所占空間:
數值類型
日期類型(datetime類型在MySQL5.6中字段長度是5個字節,在5.5中字段長度是8個字節)
字符串類型
latin1編碼的字符占1個字節,gbk編碼的字符占2個字節,utf8編碼的字符占3個字節。
c1 char(10)表示每行記錄的c1字段固定占用10個字節;而c2 varchar(10)則不一定,如果某數據行的c2字段值只占3個字節,那么該數據行的c2字段實際占5個字節,因為該類型字段所占空間大小是可變的,所以需要額外2個字節來保存字段值的長度,并且因為varchar最大字節數為65535,因此字段值最多占65533個字節。
因此,
如果事先知道某字段存儲的數據都是固定個數的字符則優先使用char以節省存儲空間。
盡量設置not null并將默認值設為‘’或0
以字符串類型字段的索引演示key_len的計算過程(以utf8編碼為例):
索引字段為char類型 + not null:key_len = 字段申明字符個數 * 3(utf8編碼的每個字符占3個字節)
- mysql>?create?table?test(
????->?id?int(10)?not?null?auto_increment,
????->?primary?key(id)
????->?)?engine=innodb?auto_increment=1?default?charset=utf8;
mysql>?alter?table?test?add?c1?char(10)?not?null;
mysql>?create?index?idx_c1?on?test(c1); 索引字段為char類型 + 可以為null:key_len = 字段申明字符個數 * 3 + 1(單獨用一個字節表示字段值是否為null)
- mysql>?alter?table?test?add?c2?char(10)?default?null;
mysql>?create?index?idx_c2?on?test(c2); 索引字段為varchar + not null,key_len = 字段申明字符個數 * 3 + 2(用來保存字段值所占字節數)
mysql>?alter?table?test?add?c3?varchar(10)?not?null;
mysql>?create?index?idx_c3?on?test(c3);varchar + 可以為null,key_len = 字段申明字符個數 * 3 + 2 + 1(用來標識字段值是否為null)
根據這個值,就可以判斷索引使用情況,特別是在使用復合索引時判斷組成該復合索引的多個字段是否都能被查詢用到。
如:
mysql>?desc?person;+-----------+-------------+------+-----+---------+----------------+
|?Field?????|?Type????????|?Null?|?Key?|?Default?|?Extra??????????|
+-----------+-------------+------+-----+---------+----------------+
|?id????????|?int(32)?????|?NO???|?PRI?|?NULL????|?auto_increment?|
|?firstName?|?varchar(30)?|?YES??|?MUL?|?NULL????|????????????????|
|?lastName??|?varchar(30)?|?YES??|?????|?NULL????|????????????????|
+-----------+-------------+------+-----+---------+----------------+
前者使用了部分復合索引,而后者使用了全部,這在索引類型一節中也提到過,是由最左前綴(定義復合索引時的第一列 )有序這一特性決定的。
ref
顯示哪一列或常量被拿來與索引列進行比較以從表中檢索行。
如上我們使用‘’到索引中檢索行。
rows
根據表統計信息及索引選用情況,大致估算出找到所需的記錄所需要讀取的行數
Extra
包含不適合在其他列中顯示但十分重要的額外信息:
Using filesort:說明mysql會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取。MySQL中無法利用索引完成的排序操作稱為“文件排序”
***************************?1.?row?***************************
???????????id:?1
??select_type:?SIMPLE
????????table:?person
???partitions:?NULL
?????????type:?index
possible_keys:?NULL
??????????key:?idx_name
??????key_len:?186
??????????ref:?NULL
?????????rows:?1
?????filtered:?100.00
????????Extra:?Using?index;?Using?filesort
使用\G代替;結尾可以使執行計劃垂直顯示。
mysql>?explain?select?*?from?person?order?by?firstName,lastName\G***************************?1.?row?***************************
???????????id:?1
??select_type:?SIMPLE
????????table:?person
???partitions:?NULL
?????????type:?index
possible_keys:?NULL
??????????key:?idx_name
??????key_len:?186
??????????ref:?NULL
?????????rows:?1
?????filtered:?100.00
????????Extra:?Using?index
Using temporary:使用了臨時表保存中間結果。MySQL在對查詢結果聚合時使用臨時表。常見于排序 order by 和分組查詢 group by。
- mysql>?insert?into?person(firstName,lastName)?values('張','三');
mysql>?insert?into?person(firstName,lastName)?values('李','三');
mysql>?insert?into?person(firstName,lastName)?values('王','三');
mysql>?insert?into?person(firstName,lastName)?values('李','明');
mysql>?select?lastName,count(lastName)?from?person?group?by?lastName;
+----------+-----------------+
|?lastName?|?count(lastName)?|
+----------+-----------------+
|?三???????|???????????????3?|
|?明???????|???????????????1?|
+----------+-----------------+
mysql>?explain?select?lastName,count(lastName)?from?person?group?by?lastName\G
***************************?1.?row?***************************
???????????id:?1
??select_type:?SIMPLE
????????table:?person
???partitions:?NULL
?????????type:?index
possible_keys:?idx_name
??????????key:?idx_name
??????key_len:?186
??????????ref:?NULL
?????????rows:?4
?????filtered:?100.00
????????Extra:?Using?index;?Using?temporary;?Using?filesort Using index:表示相應的select操作中使用了覆蓋索引(Covering Index),避免訪問了表的數據行(需要讀磁盤),效率不錯!如果同時出現Using where,表明索引被用來執行索引鍵值的查找;如果沒有同時出現Using where,表明索引用來讀取數據而非執行查找動作。
索引覆蓋:就是select的數據列只用從索引中就能夠取得,不必讀取數據行,MySQL可以利用索引返回select列表中的字段,而不必根據索引再次讀取數據文件,換句話說查詢列要被所建的索引覆蓋。
如果要使用覆蓋索引,一定要注意select列表中只取出需要的列,不可select *,因為如果將所有字段一起做索引會導致索引文件過大,查詢性能下降。
Using where:查詢使用到了where語句
Using join buffer:使用了連接緩存
Impossible where:where子句的值總是false,如
- select?*?from?person?where?id=1?and?id=2;
索引失效
如果使用explain分析SQL的執行計劃時發現訪問類型type為ALL或實際使用到的索引key為NULL,則說明該查詢沒有利用索引而導致了全表掃描,這是我們需要避免的。以下總結了利用索引的一些原則:
1、全值匹配我最愛
根據常量在索引字段上檢索時一定能夠利用到索引。
這種方式
2、最佳左前綴法則
對于復合索引檢索時一定要遵循左前綴列在前的原則。
mysql>?alter?table?test?add?c5?varchar(10)?default?null,?add?c6?varchar(10)?default?null,?add?c7?varchar(10)?default?null;mysql>?create?index?idx_c5_c6_c7?on?test(c5,c6,c7);
如果沒有左前綴列則不會利用索引:
mysql>?explain?select?*?from?test?where?c6=''\G***************************?1.?row?***************************
???????????id:?1
??select_type:?SIMPLE
????????table:?test
???partitions:?NULL
?????????type:?ALL
possible_keys:?NULL
??????????key:?NULL
??????key_len:?NULL
??????????ref:?NULL
?????????rows:?1
?????filtered:?100.00
????????Extra:?Using?where
mysql>?explain?select?*?from?test?where?c6=''?and?c7=''\G
***************************?1.?row?***************************
???????????id:?1
??select_type:?SIMPLE
????????table:?test
???partitions:?NULL
?????????type:?ALL
possible_keys:?NULL
??????????key:?NULL
??????key_len:?NULL
??????????ref:?NULL
?????????rows:?1
?????filtered:?100.00
????????Extra:?Using?where
而只要最左前綴列在前,其他列可以不按順序也可以不要,但最好不要那么做(按照定義復合索引時的列順序能達到最佳效率):
mysql>?explain?select?*?from?test?where?c5=''?and?c7=''\G***************************?1.?row?***************************
???????????id:?1
??select_type:?SIMPLE
????????table:?test
???partitions:?NULL
?????????type:?ref
possible_keys:?idx_c5_c6_c7
??????????key:?idx_c5_c6_c7
??????key_len:?33
??????????ref:?const
?????????rows:?1
?????filtered:?100.00
????????Extra:?Using?index?condition
1?row?in?set,?1?warning?(0.00?sec)
mysql>?explain?select?*?from?test?where?c5=''?and?c7=''?and?c6=''\G
***************************?1.?row?***************************
???????????id:?1
??select_type:?SIMPLE
????????table:?test
???partitions:?NULL
?????????type:?ref
possible_keys:?idx_c5_c6_c7
??????????key:?idx_c5_c6_c7
??????key_len:?99
??????????ref:?const,const,const
?????????rows:?1
?????filtered:?100.00
????????Extra:?NULL
1?row?in?set,?1?warning?(0.00?sec)
最優的做法是:
mysql>?explain?select?*?from?test?where?c5=''\Gmysql>?explain?select?*?from?test?where?c5=''?and?c6=''\G
mysql>?explain?select?*?from?test?where?c5=''?and?c6=''?and?c7=''\G
3、不在列名上添加任何操作
有時我們會在列名上進行計算、函數運算、自動/手動類型轉換,這會直接導致索引失效。
mysql>?explain?select?*?from?person?where?left(firstName,1)='張'\G***************************?1.?row?***************************
???????????id:?1
??select_type:?SIMPLE
????????table:?person
???partitions:?NULL
?????????type:?index
possible_keys:?NULL
??????????key:?idx_name
??????key_len:?186
??????????ref:?NULL
?????????rows:?4
?????filtered:?100.00
????????Extra:?Using?where;?Using?index
mysql>?explain?select?*?from?person?where?firstName='張'\G
***************************?1.?row?***************************
???????????id:?1
??select_type:?SIMPLE
????????table:?person
???partitions:?NULL
?????????type:?ref
possible_keys:?idx_name
??????????key:?idx_name
??????key_len:?93
??????????ref:?const
?????????rows:?1
?????filtered:?100.00
????????Extra:?Using?index
上面兩條SQL同樣是實現查找姓張的人,但在列名firstName上使用了left函數使得訪問類型type從ref(非唯一性索引掃描)降低到了index(全索引掃描)
4、存儲引擎無法使用索引中范圍條件右邊的列
由上圖可知c6 > ‘a’右側的列c7雖然也在復合索引idx_c5_c6_c7中,但由key_len:66可知其并未被利用上。通常索引利用率越高,查找效率越高。
5、盡量使用索引覆蓋
盡量使查詢列和索引列保持一致,這樣就能避免訪問數據行而直接返回索引數據。避免使用select *除非表數據很少,因為select *很大概率訪問數據行。
Using index表示發生了索引覆蓋
6、使用 != 或 <> 時可能會導致索引失效
7、not null對索引也有影響
若name的定義不是not null則不會有索引未利用的情況。
8、like以通配符開頭會導致索引失效
like語句以通配符%開頭無法利用索引會導致全索引掃描,而只以通配符結尾則不會。
9、join on的列只要有一個沒索引則全表掃描
10、or兩側的列只要有一個沒索引則全表掃描
11、字符串不加單引號索引失效
mysql>?explain?select?*?from?staff?where?name=123;打油詩:
全值匹配我最愛,最左前綴要遵循。
帶頭大哥不能死,中間兄弟不能斷。
索引列上少計算,范圍之后全失效。
LIKE百分比最右,覆蓋索引不寫*。
不等空值還有OR,ON的右側要注意。
VAR引號不能丟,SQL優化有訣竅。
Anwen
https://juejin.im/post/5cf3f8b6f265da1bc94ed736總結
以上是生活随笔為你收集整理的mysql 部门表_MySQL高级的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 50升油多少钱啊?
- 下一篇: 禁用mysql的sleep函数_MySQ