天天看点

SQL/MySQL--语句大全--索引--创建/删除/查看--命令/语法

简介

        本文介绍索引相关的命令。包括:创建索引、删除索引、查看索引、强制索引、索引长度等。

创建/删除 索引

官网:​​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      

执行结果

SQL/MySQL--语句大全--索引--创建/删除/查看--命令/语法
​项​ ​含义​
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个字符创建索引。这样子,就可以避免索引长度过大的问题。 

​为什么要指定长度?​

  1. 如果要创建索引的列很长,在创建索引时以及根据索引查询时,都会浪费很多时间在计算和存储上。限制其长度可以提高性能
  2. 数据库对索引的长度有限制。

​长度限制​

​项​ ​单列索引​ ​联合索引​
长度限制

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表空间)以一个类似目录的结构存储。索引要分类的话,分为前缀索引、全文本索引等;