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而不指定idEXPLAIN 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已經被刪除了提示:刪除表中的某列時,如果要刪除的列為索引的組成部分,則該列也會從索引中刪除。
如果索引中的所有列都被刪除,則整個索引將被刪除!!