mysql優化之-索引具體代碼分析:
索引是在存儲引擎中實現的,因此每種存儲引擎的索引都不一定完全相同,并且每種存儲引擎也不一定支持所有索引類型。
根據存儲引擎定義每個表的最大索引數和最大索引長度。所有存儲引擎支持每個表至少16個索引,總索引長度至少為256字節。
大多數存儲引擎有更高的限制。MYSQL中索引的存儲類型有兩種:BTREE和HASH,具體和表的存儲引擎相關;
MYISAM和InnoDB存儲引擎只支持BTREE索引;MEMORY和HEAP存儲引擎可以支持HASH和BTREE索引
索引的優點:
1、通過創建唯一索引,保證數據庫表每行數據的唯一性
2、大大加快數據查詢速度
3、在使用分組和排序進行數據查詢時,可以顯著減少查詢中分組和排序的時間
索引的缺點:
1、維護索引需要耗費數據庫資源
2、索引需要占用磁盤空間,索引文件可能比數據文件更快達到最大文件尺寸
3、當對表的數據進行增刪改的時候,因為要維護索引,速度會受到影響
索引的分類
1、普通索引和唯一索引
主鍵索引是一種特殊的唯一索引,不允許有空值
2、單列索引和復合索引
單列索引只包含單個列
復合索引指多個字段上創建的索引,只有在查詢條件中使用了創建索引時的第一個字段,索引才會被使用。使用復合索引時遵循最左前綴集合
3、全文索引
全文索引類型為FULLTEXT,在定義索引的列上支持值的全文查找,允許在這些索引列中插入重復值和空值。全文索引可以在
CHAR、VARCHAR、TEXT類型列上創建。MYSQL只有MYISAM存儲引擎支持全文索引
4、空間索引
空間索引是對空間數據類型的字段建立的索引,MYSQL中的空間數據類型有4種,
分別是GEOMETRY、POINT、LINESTRING、POLYGON。
MYSQL使用SPATIAL關鍵字進行擴展,使得能夠用于創建正規索引類型的語法創建空間索引。創建空間索引的列,必須
將其聲明為NOT NULL,空間索引只能在存儲引擎為MYISAM的表中創建
以上的索引在SQLSERVER里都支持
CREATE?TABLE?table_name[col_name?data?type] [unique|fulltext|spatial][index|key][index_name](col_name[length])[asc|desc]
unique|fulltext|spatial為可選參數,分別表示唯一索引、全文索引和空間索引;
index和key為同義詞,兩者作用相同,用來指定創建索引
col_name為需要創建索引的字段列,該列必須從數據表中該定義的多個列中選擇;
index_name指定索引的名稱,為可選參數,如果不指定,MYSQL默認col_name為索引值;
length為可選參數,表示索引的長度,只有字符串類型的字段才能指定索引長度;
asc或desc指定升序或降序的索引值存儲
普通索引
CREATE?TABLE?book?( ??bookid?INT?NOT?NULL, ??bookname?VARCHAR?(255)?NOT?NULL, ??AUTHORS?VARCHAR?(255)?NOT?NULL, ??info?VARCHAR?(255)?NULL, ??COMMENT?VARCHAR?(255)?NULL, ??year_publication?YEAR?NOT?NULL, ??INDEX?(year_publication) )?;
使用SHOW CREATE TABLE查看表結構
CREATE?TABLE?`book`?( ??`bookid`?INT(11)?NOT?NULL, ??`bookname`?VARCHAR(255)?NOT?NULL, ??`authors`?VARCHAR(255)?NOT?NULL, ??`info`?VARCHAR(255)?DEFAULT?NULL, ??`comment`?VARCHAR(255)?DEFAULT?NULL, ??`year_publication`?YEAR(4)?NOT?NULL, ??KEY?`year_publication`?(`year_publication`) )?ENGINE=MYISAM?DEFAULT?CHARSET=latin1
可以發現,book表的year_publication字段成功建立了索引其索引名字為year_publication
我們向表插入一條數據,然后使用EXPLAIN語句查看索引是否有在使用
NSERT?INTO?BOOK?VALUES(12,'NIHAO','NIHAO','文學','henhao',1990) EXPLAIN?SELECT?*?FROM?book?WHERE?year_publication=1990
因為語句比較簡單,系統判斷有可能會用到索引或者全文掃描
EXPLAIN語句輸出結果的各個行的解釋如下:
select_type: 表示查詢中每個select子句的類型(簡單 OR復雜)
type:表示MySQL在表中找到所需行的方式,又稱“訪問類型”,常見類型如下:(從上至下,效果依次變好)
possible_keys?:指出MySQL能使用哪個索引在表中找到行,查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被查詢使用
key: 顯示MySQL在查詢中實際使用的索引,若沒有使用索引,顯示為NULL
key_len?:表示索引中使用的字節數,可通過該列計算查詢中使用的索引的長度
ref?:表示上述表的連接匹配條件,即哪些列或常量被用于查找索引列上的值
rows?:表示MySQL根據表統計信息及索引選用情況,估算的找到所需的記錄所需要讀取的行數
Extra?:包含不適合在其他列中顯示但十分重要的額外信息 如using where,using index
唯一索引
唯一索引列的值必須唯一,但允許有空值。如果是復合索引則列值的組合必須唯一
建表
CREATE?TABLE?t1 ( ?id?INT?NOT?NULL, ?NAME?CHAR(30)?NOT?NULL, ?UNIQUE?INDEX?UniqIdx(id) )
SHOW CREATE TABLE t1 查看表結構
SHOW?CREATE?TABLE?t1
?CREATE?TABLE?`t1`?(??????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`id`?int(11)?NOT?NULL,??????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`name`?char(30)?NOT?NULL,???????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????UNIQUE?KEY?`UniqIdx`?(`id`)?????????????????????????????????????????????????????????????????????????????????????????????????????????????? ????????)?ENGINE=MyISAM?DEFAULT?CHARSET=utf8
可以看到id字段上已經成功建立了一個名為UniqIdx的唯一索引
創建復合索引
CREATE?TABLE?t3?( ??id?INT?NOT?NULL, ??NAME?CHAR(30)?NOT?NULL, ??age?INT?NOT?NULL, ??info?VARCHAR?(255), ??INDEX?MultiIdx?(id,?NAME,?age?(100)) )
SHOW?CREATE?TABLE?t3 CREATE?TABLE?`t3`?(????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`id`?int(11)?NOT?NULL,???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`NAME`?char(30)?NOT?NULL,????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`age`?int(11)?NOT?NULL,??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`info`?varchar(255)?DEFAULT?NULL,????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????KEY?`MultiIdx`?(`id`,`NAME`,`age`)???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ????????)?ENGINE=MyISAM?DEFAULT?CHARSET=utf8
由結果可以看到id,name,age字段上已經成功建立了一個名為MultiIdx的復合索引
我們向表插入兩條數據
INSERT?INTO?t3(id?,NAME,age,info)?VALUES(1,'小明',12,'nihao'),(2,'小芳',16,'nihao')
使用EXPLAIN語句查看索引使用情況
EXPLAIN?SELECT?*?FROM?t3?WHERE?id=1?AND?NAME='小芳'
可以看到? possible_keys和 key 為MultiIdx證明使用了復合索引
?id??select_type??table???type????possible_keys??key???????key_len??ref????????????rows??Extra?????? ------??-----------??------??------??-------------??--------??-------??-----------??------??----------- ?????1??SIMPLE???????t3??????ref?????MultiIdx???????MultiIdx??94???????const,const???????1??Using?where
如果我們只指定name而不指定id
EXPLAIN?SELECT?*?FROM?t3?WHERE??NAME='小芳' ????id??select_type??table???type????possible_keys??key?????key_len??ref???????rows??Extra?????? ------??-----------??------??------??-------------??------??-------??------??------??----------- ?????1??SIMPLE???????t3??????ALL?????(NULL)?????????(NULL)??(NULL)???(NULL)???????2??Using?where
結果跟SQLSERVER一樣,也是不走索引,?possible_keys和key都為NULL
全文索引
FULLTEXT索引可以用于全文搜索。只有MYISAM存儲引擎支持FULLTEXT索引,并且只支持CHAR、VARCHAR和TEXT類型
全文索引不支持過濾索引。
CREATE?TABLE?t4?( ??id?INT?NOT?NULL, ??NAME?CHAR(30)?NOT?NULL, ??age?INT?NOT?NULL, ??info?VARCHAR?(255), ??FULLTEXT?INDEX?FulltxtIdx?(info) )?ENGINE?=?MYISAM
由于MYSQL5.6默認存儲引擎為InnoDB,這里創建表的時候要修改表的存儲引擎為MYISAM,不然創建索引會出錯
SHOW?CREATE?TABLE?t4
Table???Create?Table???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ------??------------------------------------------------------------------------------------------------------------------------------------------------------ ---------------------------------------------------------- t4??????CREATE?TABLE?`t4`?(????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`id`?int(11)?NOT?NULL,???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`name`?char(30)?NOT?NULL,????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`age`?int(11)?NOT?NULL,??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`info`?varchar(255)?DEFAULT?NULL,????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????FULLTEXT?KEY?`FulltxtIdx`?(`info`)???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ????????)?ENGINE=MyISAM?DEFAULT?CHARSET=utf8
由結果可以看到,info字段上已經成功建立名為FulltxtIdx的FULLTEXT索引。
全文索引非常適合大型數據集合
空間索引
空間索引必須在?MYISAM類型的表中創建,而且空間類型的字段必須為非空
建表t5
CREATE?TABLE?t5 (g?GEOMETRY?NOT?NULL?,SPATIAL?INDEX?spatIdx(g))ENGINE=MYISAM
SHOW?CREATE?TABLE?t5 TABLE???CREATE?TABLE??????????????????????????????????????????????????????????????????????????????????????????????????? ------??--------------------------------------------------------------------------------------------------------------- t5??????CREATE?TABLE?`t5`?(???????????????????????????????????????????????????????????????????????????????????????????? ??????????`g`?GEOMETRY?NOT?NULL,??????????????????????????????????????????????????????????????????????????????????????? ??????????SPATIAL?KEY?`spatIdx`?(`g`)?????????????????????????????????????????????????????????????????????????????????? ????????)?ENGINE=MYISAM?DEFAULT?CHARSET=utf8
可以看到,t5表的g字段上創建了名稱為spatIdx的空間索引。注意創建時指定空間類型字段值的非空約束
并且表的存儲引擎為MYISAM
已經存在的表上創建索引
在已經存在的表中創建索引,可以使用ALTER TABLE或者CREATE INDEX語句
1、使用ALTER TABLE語句創建索引,語法如下
ALTER?TABLE?table_name?ADD?[UNIQUE|FULLTEXT|SPATIAL][INDEX|KEY] [index_name](col_name[length],...)[ASC|DESC]
與創建表時創建索引的語法不同,在這里使用了ALTER TABLE和ADD關鍵字,ADD表示向表中添加索引
在t1表中的name字段上建立NameIdx普通索引
ALTER?TABLE?t1?ADD?INDEX?NameIdx(NAME)
添加索引之后,使用SHOW INDEX語句查看指定表中創建的索引
SHOW?INDEX?FROM?t1 TABLE???Non_unique??Key_name??Seq_in_index??Column_name??COLLATION??Cardinality??Sub_part??Packed??NULL????Index_type??COMMENT??Index_comment ------??----------??--------??------------??-----------??---------??-----------??--------??------??------??----------??-------??------------- t1???????????????0??UniqIdx??????????????1??id???????????A????????????????????0????(NULL)??(NULL)??????????BTREE????????????????????????????? t1???????????????1??NameIdx??????????????1??NAME?????????A???????????????(NULL)????(NULL)??(NULL)??????????BTREE
各個參數的含義
1、TABLE:要創建索引的表
2、Non_unique:索引非唯一,1代表是非唯一索引,0代表唯一索引
3、Key_name:索引的名稱
4、Seq_in_index:該字段在索引中的位置,單列索引該值為1,復合索引為每個字段在索引定義中的順序
5、Column_name:定義索引的列字段
6、Sub_part:索引的長度
7、NULL:該字段是否能為空值
8、Index_type:索引類型
可以看到,t1表已經存在了一個唯一索引
在t3表的age和info字段上創建復合索引
ALTER?TABLE?t3?ADD?INDEX?t3AgeAndInfo(age,info)
使用SHOW INDEX查看表中的索引
SHOW?INDEX?FROM?t3
Table???Non_unique??Key_name??????Seq_in_index??Column_name??Collation??Cardinality??Sub_part??Packed??Null????Index_type??Comment??Index_comment ------??----------??------------??------------??-----------??---------??-----------??--------??------??------??----------??-------??------------- t3???????????????1??MultiIdx?????????????????1??id???????????A???????????????(NULL)????(NULL)??(NULL)??????????BTREE????????????????????????????? t3???????????????1??MultiIdx?????????????????2??NAME?????????A???????????????(NULL)????(NULL)??(NULL)??????????BTREE????????????????????????????? t3???????????????1??MultiIdx?????????????????3??age??????????A???????????????(NULL)????(NULL)??(NULL)??????????BTREE????????????????????????????? t3???????????????1??t3AgeAndInfo?????????????1??age??????????A???????????????(NULL)????(NULL)??(NULL)??????????BTREE????????????????????????????? t3???????????????1??t3AgeAndInfo?????????????2??info?????????A???????????????(NULL)????(NULL)??(NULL)??YES?????BTREE
可以看到表中的字段的順序,第一個位置是age,第二個位置是info,info字段是可空字段
創建表t6,在t6表上創建全文索引
CREATE?TABLE?t6 ( ??id?INT?NOT?NULL, ??info?CHAR(255) )ENGINE=?MYISAM;
注意修改ENGINE參數為MYISAM,MYSQL默認引擎InnoDB不支持全文索引
使用ALTER TABLE語句在info字段上創建全文索引
ALTER?TABLE?t6?ADD?FULLTEXT?INDEX?infoFTIdx(info)
使用SHOW INDEX查看索引情況
SHOW?INDEX?FROM?t6
Table???Non_unique??Key_name???Seq_in_index??Column_name??Collation??Cardinality??Sub_part??Packed??Null????Index_type??Comment??Index_comment ------??----------??---------??------------??-----------??---------??-----------??--------??------??------??----------??-------??------------- t6???????????????1??infoFTIdx?????????????1??info?????????(NULL)??????????(NULL)????(NULL)??(NULL)??YES?????FULLTEXT
創建表t7,并在空間數據類型字段g上創建名稱為spatIdx的空間索引
CREATE?TABLE?t7(g?GEOMETRY?NOT?NULL)ENGINE=MYISAM;
使用ALTER TABLE在表t7的g字段建立空間索引
ALTER?TABLE?t7?ADD?SPATIAL?INDEX?spatIdx(g)
使用SHOW INDEX查看索引情況
SHOW?INDEX?FROM?t7
Table???Non_unique??Key_name??Seq_in_index??Column_name??Collation??Cardinality??Sub_part??Packed??Null????Index_type??Comment??Index_comment ------??----------??--------??------------??-----------??---------??-----------??--------??------??------??----------??-------??------------- t7???????????????1??spatIdx??????????????1??g????????????A???????????????(NULL)????????32??(NULL)??????????SPATIAL
2、使用CREATE INDEX語句創建索引,語法如下
CREATE?[UNIQUE|FULLTEXT|SPATIAL]??INDEX?index_name ON?table_name(col_name[length],...)??[ASC|DESC]
可以看到CREATE INDEX語句和ALTER INDEX語句的基本語法一樣,只是關鍵字不同。
我們建立一個book表
CREATE?TABLE?book?( ??bookid?INT?NOT?NULL, ??bookname?VARCHAR?(255)?NOT?NULL, ??AUTHORS?VARCHAR?(255)?NOT?NULL, ??info?VARCHAR?(255)?NULL, ??COMMENT?VARCHAR?(255)?NULL, ??year_publication?YEAR?NOT?NULL )
建立普通索引
CREATE?INDEX?BkNameIdx?ON?book(bookname)
建立唯一索引
CREATE?UNIQUE?INDEX?UniqidIdx?ON?book(bookId)
建立復合索引
CREATE?INDEX?BkAuAndInfoIdx?ON?book(AUTHORS(20),info(50))
建立全文索引,我們drop掉t6表,重新建立t6表
DROP?TABLE?IF?EXISTS?t6 CREATE?TABLE?t6 ( ??id?INT?NOT?NULL, ??info?CHAR(255) )ENGINE=?MYISAM; CREATE?FULLTEXT?INDEX?infoFTIdx?ON?t6(info);
建立空間索引,我們drop掉t7表,重新建立t7表
DROP?TABLE?IF?EXISTS?t7 CREATE?TABLE?t7(g?GEOMETRY?NOT?NULL)ENGINE=MYISAM; CREATE?SPATIAL?INDEX?spatIdx??ON?t7(g)
刪除索引
MYSQL中使用ALTER TABLE或者DROP INDEX語句來刪除索引,兩者實現相同功能
1、使用ALTER TABLE刪除索引
?語法
ALTER?TABLE?table_name?DROP?INDEX?index_name
ALTER?TABLE?book?DROP?INDEX?UniqidIdx
SHOW?CREATE?TABLE?book
Table???Create?Table?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ------??---------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------- book????CREATE?TABLE?`book`?(????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`bookid`?int(11)?NOT?NULL,?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`bookname`?varchar(255)?NOT?NULL,??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`authors`?varchar(255)?NOT?NULL,???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`info`?varchar(255)?DEFAULT?NULL,??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`comment`?varchar(255)?DEFAULT?NULL,???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`year_publication`?year(4)?NOT?NULL,???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????KEY?`BkNameIdx`?(`bookname`),??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????KEY?`BkAuAndInfoIdx`?(`authors`(20),`info`(50))????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ????????)?ENGINE=MyISAM?DEFAULT?CHARSET=utf8
可以看到,book表中已經沒有名為UniqidIdx的唯一索引,刪除索引成功
注意:AUTO_INCREMENT約束字段的唯一索引不能被刪除!!
2、使用DROP INDEX 語句刪除索引
DROP?INDEX?index_name?ON?table_name
DROP?INDEX?BkAuAndInfoIdx?ON?book
SHOW?CREATE?TABLE?book; Table???Create?Table??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ------?? ------------------------------------------------------------------------------------------------------------------------------------------------------------------ --------------------------------------------------------------------------------------------------------------------------------------------- book????CREATE?TABLE?`book`?(?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`bookid`?int(11)?NOT?NULL,??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`bookname`?varchar(255)?NOT?NULL,???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`authors`?varchar(255)?NOT?NULL,????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`info`?varchar(255)?DEFAULT?NULL,???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`comment`?varchar(255)?DEFAULT?NULL,????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????`year_publication`?year(4)?NOT?NULL,????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????KEY?`BkNameIdx`?(`bookname`)????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ????????)?ENGINE=MyISAM?DEFAULT?CHARSET=utf8
可以看到,復合索引BkAuAndInfoIdx已經被刪除了
提示:刪除表中的某列時,如果要刪除的列為索引的組成部分,則該列也會從索引中刪除。
如果索引中的所有列都被刪除,則整個索引將被刪除!!