簡介
本文介紹索引相關的指令。包括:建立索引、删除索引、檢視索引、強制索引、索引長度等。
建立/删除 索引
官網:MySQL :: MySQL 8.0 Reference Manual :: 13.1 Data Definition Statements
索引類型 | 建立索引的指令 | 删除索引的指令 |
普通索引 | 法1:直接建立索引: CREATE INDEX index_name ON `table_name` (column_name(length)) 法2:修改表結構的方式添加索引 ALTER TABLE `table_name` ADD INDEX index_name (column_name(length)) 法3:建立表的時候同時建立索引 CREATE TABLE `table_name` ( `id` int(11) NOT NULL AUTO_INCREMENT , `title` char(255) CHARACTER NOT NULL , PRIMARY KEY (`id`), INDEX index_name (title(length)) ); | DROP INDEX index_name ON `table_name`; 或:ALTER TABLE `table_name` DROP INDEX index_name |
唯一索引 | 法1:建立唯一索引 CREATE UNIQUE INDEX indexName ON table(column(length)) 法2:修改表結構 ALTER TABLE `table_name` ADD UNIQUE INDEX indexName (column(length)) 法3:建立表的時候直接指定 CREATE TABLE `table_name` ( `id` int(11) NOT NULL AUTO_INCREMENT , `title` char(255) CHARACTER NOT NULL , UNIQUE INDEX indexName (title(length)) ); | DROP INDEX index_name ON `table_name`; 或:ALTER TABLE table_name DROP INDEX index_name |
主鍵索引 | 不能用CREATE PRIMARY INDEX這種方式直接建立。 法1:修改表結構的方式添加索引 ALTER TABLE `table_name` ADD CONSTRAINT FK_ID PRIMARY KEY(字段名) 法2:建表的時候同時建立主鍵索引: CREATE TABLE `table_name` ( `id` int(11) NOT NULL AUTO_INCREMENT , `title` char(255) NOT NULL , PRIMARY KEY (`id`) ); | DROP INDEX `PRIMARY` ON `table_name`; 或:ALTER TABLE `table_name` DROP PRIMARY KEY 對主鍵來說,删除時index_name必須是`PRIMARY`,這是保留的。 添加 AUTO_INCREMENT 限制字段的唯一索引不能被删除。 |
外鍵索引 | 法1:建立表的時候直接指定 CREATE TABLE `t_class`( id int unsigned auto_increment not null, name varchar(10), primary key(id) ); CREATE TABLE `t_student`( id int unsigned auto_increment not null primary key, sid int unsigned default null, CONSTRAINT fk_student_class FOREIGN KEY (sid) REFERENCES class (id) ); 法2:修改表結構 ALTER TABLE tb1 ADD CONSTRAINT FK_ID FOREIGN foreign KEY (`gid`) REFERENCES tb2(`id`); | DROP INDEX index_name ON `table_name` 或:ALTER TABLE `table_name` DROP FOREIGN KEY 外鍵名 |
全文索引 | CREATE TABLE `table` ( `id` int(11) NOT NULL AUTO_INCREMENT , `title` char(255) CHARACTER NOT NULL , `content` text CHARACTER NULL , PRIMARY KEY (`id`), FULLTEXT (content) ); | |
聯合索引 | ALTER TABLE `table` ADD INDEX name_city_age (name,city,age); |
一條語句建立多條索引:
ALTER TABLE `t_user` ADD INDEX idx_user_name (`user_name`), ADD INDEX idx_phone (`phone`);
檢視索引
檢視索引
指令
SHOW INDEX FROM table_name
官網
https://dev.mysql.com/doc/refman/5.7/en/show-index.html
示例
建表、建索引
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id 自增,主鍵',
`name` varchar(12) NOT NULL DEFAULT '' COMMENT '使用者姓名',
`score` int(3) NOT NULL COMMENT '分數',
`class` varchar(12) NOT NULL COMMENT '班級',
`school_id` int(11) NOT NULL COMMENT '學校id',
PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=192904 DEFAULT CHARSET=utf8;
CREATE INDEX name_Index ON `user`(`name`(5));
CREATE INDEX school_Index ON `user`(`school_id`);
CREATE INDEX class_score_Index ON `user`(`class`, `score`);
檢視索引
SHOW INDEX FROM user
執行結果

項 | 含義 |
table | 表的名稱 |
Non_unique | 如果該列索引中不包括重複的值則為0否則為1 |
Key_name | 索引名稱,如果是主鍵的話則為PRIMARY |
Seq_in_index | 索引中序列的序列号,從1開始。如果是組合索引那麼按照字段在建立索引時的順序排列如('c1','c2','c3')那麼分别為1,2,3 |
Column_name | 列的名稱 |
Collation | 列以什麼方式存儲在索引中。在MySQL中,有值‘A’(升序)或NULL(無分序) |
Cardinality | 索引中唯一值的數目的估計值,通過運作ANALYZETABLEormyisamchk-a來更新,數根據被存儲為整數的統計資料來計數,是以對于小表該值沒必要太過于精确,而對于大資料量的表來說,改值越大當進行聯合時,MySQL使用該索引的機會就越大。 |
Sub_part | 索引的長度,如果是部分被編入索引則該值表示索引的長度,如果是整列被編入索引則為null,例如name_Index和school_Index兩個索引,比較一下上面兩個索引建立時候的差別 |
Packed | 訓示關鍵字如何被壓縮。如果沒有被壓縮,則為NULL |
Null | 如果該列的值有NULL,則是YES否則為NO.. |
Index_type | 所用索引方法(BTREE,FULLTEXT,HASH,RTREE) |
Commnet | 關于在其列中沒有描述的索引的資訊 |
Index_comment | 為索引建立時提供了一個注釋屬性的索引的任何評論 |
檢視索引狀态
指令
SHOW STATUS LIKE 'Handler_read%';
示例:
handler_read_key:越高越好,表示使用索引查詢到的次數
handler_read_rnd_next:這個值越高,說明查詢低效
強制/忽略 索引
指令
USE/FORCE/IGNORE INDEX(index_name)
作用
希望使用/強制使用/不使用 某索引
FORCE INDEX 和 USE INDEX 的差別
-
- USE INDEX 給MYSQL優化器一種選擇的可能,具體的MYSQL優化器再進行優化選擇
- FORCE INDEX 是強制MYSQL優化器使用某個索引
示例1:use index
如在test1中查詢。test1 有兩個字段:主鍵id,索引 name。
預設情況:使用id的索引(加粗部分)
explain select id from test1;
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | test1 | index | NULL | PRIMARY | 4 | NULL | 18 | Using index |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
指定希望使用的索引:最終使用了指定的索引(加粗部分)
explain select id from test1 use index(name);
+------+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
| 1 | SIMPLE | test1 | index | NULL | name_index | 6 | NULL | 18 | Using index |
+------+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
示例2:force index
explain select id from test1 force index(name);
+------+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
| 1 | SIMPLE | test1 | index | NULL | name_index | 6 | NULL | 18 | Using index |
+------+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
示例3:ignore index
預設情況:使用索引
explain select name from test1 ;
+------+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
| 1 | SIMPLE | test1 | index | NULL | name_index | 6 | NULL | 18 | Using index |
+------+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
不使用索引:發現沒使用索引
explain select name from test1 ignore index(name);
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | test1 | ALL | NULL | NULL | NULL | NULL | 18 | |
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
索引長度
索引長度的含義
建立索引的指令有兩種寫法(指定或者不指定長度):
-
- CREATE INDEX index_name ON table_name (column_name)
- CREATE INDEX index_name ON table_name (column_name(length))
如果确實需要在單個很大的列上建立索引,或者需要在多個很大的列上建立聯合索引,而又超過了索引的長度限制,解決辦法是在建索引時限制索引prefix的大小(也就是上邊指令中的length)。
例如:
create index yarn_app_result_i4 on yarn_app_result (flow_exec_id(100), another_column(50));
這樣,在建立索引時就會限制使用的每個列的最大長度。如上的例子中,在建立聯合索引時,最多使用列flow_exec_id中前100個字元建立索引,最多使用another_column中前50個字元建立索引。這樣子,就可以避免索引長度過大的問題。
為什麼要指定長度?
-
- 如果要建立索引的列很長,在建立索引時以及根據索引查詢時,都會浪費很多時間在計算和存儲上。限制其長度可以提高性能
- 資料庫對索引的長度有限制。
長度限制
項 | 單列索引 | 聯合索引 |
長度限制 | MySQL5.6:預設不能超過767bytes MySQL5.7:預設不超過3072bytes | 預設不超過3072bytes |
長度限制來由 | 767位元組:256×3-1。這個3是字元最大占用空間(utf8)。 3072位元組:5.5以後,開始支援4個位元組的uutf8,255×4>767。預設情況下:innodb_large_prefix=OFF,最大位元組數為767。可通過以下方法設定為3072:innodb_large_prefix=ON、innodb_file_format=barracuda、innodb_file_per_table=ON ,且Innodb表的存儲格式為 DYNAMIC 或 COMPRESSED | InnoDB一個page的預設大小是16k。由于是Btree組織,要求葉子節點上一個page至少要包含兩條記錄(否則就退化連結清單了)。是以一個記錄最多不能超過8k。 又由于InnoDB的聚簇索引結構,一個二級索引要包含主鍵索引,是以每個單個索引不能超過4k (極端情況,pk和某個二級索引都達到這個限制)。 由于需要預留和輔助空間,扣掉後不能超過3500,取個“整數”就是(1024*3)。 |
指令示例
CREATE TABLE `tb` (
`a` varchar(255) DEFAULT NULL,
`b` varchar(255) DEFAULT NULL,
`c` varchar(255) DEFAULT NULL,
`d` varchar(255) DEFAULT NULL,
`e` varchar(255) DEFAULT NULL,
KEY `idx_a` (`a`,`b`,`c`,`d`,`e`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
報錯: ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
原因:建立的聯合索引idx_a的長度為:255*3*5= 3825 bytes ,大于最大值 3072 bytes
index和key的差別
官方解釋:
KEY通常是INDEX的同義詞。當在列定義中給出時,鍵屬性PRIMARY KEY也可以被指定為KEY。這是為了與其他資料庫系統相容而實作的。
KEY is normally a synonym for INDEX. The key attribute PRIMARY KEY can also be specified as just KEY when given in a column definition. This was implemented for compatibility with other database systems.
如果語句中隻有key,沒有其他輔助,則表示普通索引。
示例如下:
mysql> create table t(a int,key idx_a(a))engine =innodb;
Query OK, 0 rows affected (0.24 sec)
mysql> desc t;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| a | int(11) | YES | MUL | NULL | |
+-------+---------+------+-----+---------+-------+
1 row in set (0.00 sec)
若語句中結合其他,如:primary,則結果如下:
mysql> create table t1(a int, primary key idx_a(a))engine =innodb;
Query OK, 0 rows affected (0.44 sec)
mysql> desc t1;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| a | int(11) | NO | PRI | NULL | |
+-------+---------+------+-----+---------+-------+
key:
key 是資料庫的實體結構,它包含兩層意義,一是限制(偏重于限制和規範資料庫的結構完整性),二是索引(輔助查詢用的)。包括primary key, unique key, foreign key 等。
primary key 有兩個作用:一是限制作用(constraint),規範一個存儲主鍵和唯一性,同時在此key上建立了一個index;
unique key 有兩個作用:一是限制作用(constraint),規範資料的唯一性,同時也在這個key上建立了一個index;
foreign key也有兩個作用:一是限制作用(constraint),規範資料的引用完整性,但同時也在這個key上建立了一個index
可見,mysql的key是同時具有constraint和index的意義,這點和其他資料庫表現的可能有差別。(至少在Oracle上建立外鍵,不會自動建立index),是以建立key也有如下幾種方式:
(1)在字段級以key方式建立, 如 create table t (id int not null primary key);
(2)在表級以constraint方式建立,如create table t(id int, CONSTRAINT pk_t_id PRIMARY key (id));
(3)在表級以key方式建立,如create table t(id int, primary key (id));
其它key建立類似,但不管那種方式,既建立了constraint,又建立了index,隻不過index使用的就是這個constraint或key。
index:
index是資料庫的實體結構,它隻是輔助查詢的,它建立時會在另外的表空間(mysql中的innodb表空間)以一個類似目錄的結構存儲。索引要分類的話,分為字首索引、全文本索引等;