1. 程式人生 > >MySQL優化之——索引

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_keyskey 為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_keyskey都為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已經被刪除了

提示:刪除表中的某列時,如果要刪除的列為索引的組成部分,則該列也會從索引中刪除。

如果索引中的所有列都被刪除,則整個索引將被刪除!!