【MySQL】索引

目录

[一. 认识索引](#一. 认识索引)

[1.1 索引使用的数据结构](#1.1 索引使用的数据结构)

Hash

二叉搜索树

N叉树

B+树(高频面试题)

[1.2 MySQL中的页](#1.2 MySQL中的页)

页文件头和页文件尾

页主体

页目录

[1.3 索引分类](#1.3 索引分类)

主键索引

普通索引

唯一索引

聚集索引

非聚集索引

索引覆盖

​编辑

[二. 使用索引](#二. 使用索引)

[2.1 自动创建](#2.1 自动创建)

[2.2 创建主键索引](#2.2 创建主键索引)

[2.3 创建唯一索引](#2.3 创建唯一索引)

[2.4 创建普通索引](#2.4 创建普通索引)

[2.5 创建复合索引](#2.5 创建复合索引)

[2.6 查看索引](#2.6 查看索引)

[2.7 删除主键索引](#2.7 删除主键索引)

[2.8 删除其他索引](#2.8 删除其他索引)

[2.9 创建索引的注意事项](#2.9 创建索引的注意事项)

[2.10 查看查询时是否使用索引](#2.10 查看查询时是否使用索引)


一. 认识索引

数据库中的索引是一种用于提高数据库查询性能的数据结构,索引就像一本书的目录,通过存储数据的特定列的值以及数据行的物理位置快速定位和访问所需数据,比如字典的目录页我们可以按照笔画、偏旁等排序的目录快速查找到想要的字。

比如上图中的按照拼音首字母进行排序的目录,我们可以根据首字母来缩小范围,更加快速的查找目标的字。

1.1 索引使用的数据结构

上述说了索引其实是一种提高查询性能的数据结构,那么我们来分析一下索引使用了哪种数据结构

Hash

说到查询速度,我们不得不想到使用Hash表提高查询速度,毕竟Hash表的查询速度可是在O(1)的,但是在MySQL中并没有使用Hash表作为索引的默认数据结构,这是因为Hash表是通过hashcode再进行Hash函数找到值的下标进行查询的只能单个查询,Hash表不支持范围查找。

二叉搜索树

既然Hash表不行,那么我们自然能够想到二叉搜索树,二叉搜索树的中序遍历得出来的就是一个有序的序列,是支持范围查询的,并且查询的时间复杂度为O(logN)也是非常快速的,但是二叉搜索树的性能非常不稳定,二叉搜索树在本身有序的情况下是一个单边树,时间复杂度为O(N)

我们的数据是保存在磁盘上的,每一次通过父节点查找子节点,都会发生一次磁盘IO,磁盘IO是制约整个数据库性能的主要因素,并且二叉搜索树的度为2,当数据多一点时,我们没有办法保证树的高度,当树的高度越高发生磁盘IO的次数就越多,数据库的性能就越差,因此也没有使用二叉搜索树作为索引的默认数据结构。

N叉树

上述二叉搜索树因为树高的问题并没有作为索引的默认数据结构,那么我们就尝试扩大树的度来降低树的高度,于是我们现在来看看N叉树:

此时每个节点的子节点都可以超过俩个,可以有效的解决树高的问题,从而减少磁盘IO的次数,时间复杂度为O(logN),但是查询时发生磁盘IO的次数不稳定,其实N叉树已经可以满足我们的需求了,但是还有一个更好的数据结构(B+树)保证了磁盘IO的次数是稳定的。

B+树(高频面试题)

B+树是一种经常用于数据库和文件系统等场合的平衡查找树,我们MySQL种索引默认采用的就是这个数据结构,那么我们来看看B+树和N叉树的区别:

B+树和N叉树的区别:

  1. B+树的叶子节点之间有一个相互连接的引用,通过一个叶子节点就可以找到与它相邻的兄弟节点,并且B+树的节点是顺序递增的,这里MySQL组织叶子节点时使用的是双向循环链表
  2. 非叶子节点的值也包含在叶子节点中,也意味着叶子节点有所有的数据,而B+树的非叶子节点中只包含对子节点的引用,没有保存真实的数据,所有真实的数据都保存在叶子节点中
  3. B+在相同树高的情况下,查找任意一个元素发生磁盘IO的次数都是一样的,性能均衡

B+树的特点:

  • B+树查找数据的时间复杂度为O(logN)
  • B+树可以有效的控制树高,减少磁盘IO提升性能
  • B+树的非叶子节点不存储数据,所有的数据都保存在叶子节点中
  • B+树的叶子节点构成一个有序的链表,按照key值进行排序,保证数据的有序性

1.2 MySQL中的页

在.ibd文件中的结构体就是页,页是内存与磁盘交互的最小单元,**默认大小为16kb,**每次内存与磁盘进行交互时最少会从磁盘中读取一页(也就是读取16kb大小的数据),磁盘中每个页内部的地址都是连续的

为什么操作系统读取的大小为4kb,但是MySQL却要一次性读取16kb的数据呢?

这是因为在使用数据的过程中,根据局部性原理,将来要使用的数据大概率与当前访问的数据在内存空间上是邻近的,所以一次从磁盘上读取16kb的数据放入内存中,下次使用的数据要是还在这16kb的数据中,就可以直接从内存中读取,就不要再进行磁盘IO操作,从而提高性能

页在磁盘上的什么地方放着呢?

在我们的.idb文件中就管理着很多的页,但是在MySQL中也有着很多不同类型的页,最常用的就是存储数据和索引的**"索引页"或者称为"数据页"**,那么我们来看看数据页的基本结构:

页文件头和页文件尾

那么我们分别来查看一下页文件头和页文件尾中包含的信息:

这里重点关注上一页页号和下一页页号,这两个属性就像双向链表中的上一个节点的内存地址和下一个节点的内粗地址,通过这两个属性就可以将页与页之间链接起来,形成一个双向链表。

页主体

页主体的部分区域才是保存真实数据的主要区域,当创建一个新的页时,都会自动分配两行,一个是页内最小行一个是页内最大行,这两行不存储任何真实的数据,而是数据行链表的头和尾

此时第一个数据行有一个记录下一行地址偏移量的区域 next_record 将页内所有的数据行组成一个单向链表。当向这个新页插入数据时,会将最小行连接到第一个数据行,最后一行真实数据连接到最大行,随着更多的数据插入,会按照主键从小到大的顺序进行链接:

但是一个页的大小有16kb,可以存非常多的数据行,在一个页中进行数据行的遍历也很费时该如何进行优化呢?

页目录

如果每次查询数据都要沿着链表进行遍历,那么查询速度是很低效的,为了提高查询效率,为页中引入了页目录的概念,将页内包括头行、尾行在内的所有行进行分组,约定头行单独为一组,其他每个组最多8条数据,页目录中的每个位置称为一个槽,每个槽都对应了一个分组,一旦分组中的数据行超过分组的上限时,就会自动分裂中一个新的分组:

再添加一条数据时,自动分裂新的分组:

槽和分组是一 一对应的关系,槽中记录着当前分组的最后条记录的主键值,如果现在查询主键为7的记录,首先会先判断槽中的值,找到数据可能存在的分组,再去分组逐条寻找,最终找到目标数据行。

为了提高查询效率,InnoDB在查找数据行时采用二分查找来解决查询效率问题

1.3 索引分类

主键索引

  • 当一个表上定义了一个主键时,就会自动创建主键索引
  • 推荐为每个表定义一个主键,如果没有逻辑上唯一且非空的列可以使用主键,则可以添加一个自增列作为主键列

普通索引

  • 最基本的索引类型,没有唯一性的限制
  • 可以为多列创建一个组合索引,称为复合索引或者组合索引,复合索引中包括了创建索引时的所有列

比如开头演示的字母目录:

唯一索引

  • 当一个表中定义一个唯一键时,会自动创建唯一索引
  • 与普通索引的区别在于唯一索引的列是不允许重复的

聚集索引

  • 与主键索引是同义词
  • 如果没有为表定义主键,InnoDB会使用第一个unique 和 not null的列作为聚集索引
  • 如果表中没有主键或者合适的索引,InnoDB会为新插入的行生成一个行号,并用6字节的ROW_ID字段记录,该字段单调递增,并使用该字段作为索引

非聚集索引

  • 聚集索引以外的索引称为⾮聚集索引或⼆级索引
  • ⼆级索引中的每条记录都包含该⾏的主键列,以及⼆级索引指定的列。
  • InnoDB使⽤这个主键值来搜索聚集索引中的⾏,这个过程称为回表查询

回表查询:

索引覆盖

二. 使用索引

认识完索引,那么现在来看看该如何使用索引吧

2.1 自动创建

  • 当我们为表加上主键约束、外键约束、唯一约束时,MySQL会为对应的列自动创建一个索引
  • 如果表不指定任何约束时,则会自动为每一列生成一个索引并用Row_ID进行标识

2.2 创建主键索引

创建主键索引时,当我们创建表时加上主键约束就会自动创建主键索引:

复制代码
-- 方法一:创建表时创建主键
create table test1_pri(
  id bigint primary key auto_increment,
  name varchar(20)
);

-- 方法二: 创建表时单独指定主键列
create table test2_pri(
  id bigint auto_increment,
  name varchar(20),
  primary key(id)
);

-- 方法三:修改表中的列为主键索引
create table test3_pri(
  id bigint,
  name varchar(20)
);

alter table test3_pri add PRIMARY key (id);
alter table test3_pri modify id bigint auto_increment;

mysql> show tables;
+----------------------+
| Tables_in_test_index |
+----------------------+
| test1_pri            |
| test2_pri            |
| test3_pri            |
+----------------------+
3 rows in set (0.00 sec)

mysql> desc test1_pri;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | bigint      | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)

2.3 创建唯一索引

创建唯一索引与主键索引类似,当我们创建表时加上唯一约束,也会自动创建唯一索引:

复制代码
-- 方法一:创建表时加上唯一约束
create table test1_unique(
  id bigint primary key auto_increment,
  name varchar(20) UNIQUE -- 此时会默认生成一个唯一索引名
);

-- 方法二:创建表时单独指定唯一列
create table test2_unique(
  id bigint primary key auto_increment,
  name varchar(20),
  constraint unique un_name1 (name) -- 指定唯一索引名
);

-- 方法三:修改表中的列为唯一索引
create table test3_unique(
  id bigint primary key auto_increment,
  name varchar(20)
);
alter table test3_unique add unique un_name2 (name); -- 指定唯一索引名



mysql> show tables;
+----------------------+
| Tables_in_test_index |
+----------------------+
| test1_pri            |
| test1_unique         |
| test2_pri            |
| test2_unique         |
| test3_pri            |
| test3_unique         |
+----------------------+
6 rows in set (0.00 sec)

mysql> desc test1_unique;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | bigint      | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  | UNI | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec

2.4 创建普通索引

创建普通索引的时机:

  1. 创建表的时候如果能预测到某个列是一个频繁查询的列,则可以直接在这个列上创建索引,但是数据量比较小的系统,一般当表中的数据量达到十几万的时候再去创建索引,因为创建一个索引就需要多维护一个索引树,当表中的数据比较少时,有时候会使用全表扫描甚至比使用索引块(是否使用索引由MySQL内部的优化器决定)
  2. 随着业务数据增加,在版本迭代的过程中添加索引,当系统运行的过程中出现的运行时间比较长的SQL,就可以针对性添加索引

创建普通索引的方式:

复制代码
-- 方法一:创建表时指定索引列
create table test_index1(
  id bigint PRIMARY KEY auto_increment,
  name varchar(20)unique,
  sno varchar(10),
  index(sno) -- 单独指定索引列
);

-- 方法二:修改表中的列为普通索引
create table test_index2(
  id bigint PRIMARY KEY auto_increment,
  name varchar(20)unique,
  sno varchar(10)
);
alter table test_index2 add index index1_sno (sno); -- 加上索引名

-- 方法三:单独创建索引并指定索引名
create table test_index3(
  id bigint PRIMARY KEY auto_increment,
  name varchar(20)unique,
  sno varchar(10)
);
create index index2_sno on test_index3(sno);-- 指定表中的列

mysql> show tables;
+----------------------+
| Tables_in_test_index |
+----------------------+
| test1_pri            |
| test1_unique         |
| test2_pri            |
| test2_unique         |
| test3_pri            |
| test3_unique         |
| test_index1          |
| test_index2          |
| test_index3          |
+----------------------+
9 rows in set (0.00 sec)

mysql> desc test_index1;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | bigint      | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  | UNI | NULL    |                |
| sno   | varchar(10) | YES  | MUL | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

2.5 创建复合索引

复制代码
-- 方法一:创建表时指定索引列
create table tests_indexs1 (
 id bigint primary key auto_increment,
 name varchar(20),
 sno varchar(10),
 class_id bigint,
 index (sno, class_id) -- 通过学号和班级id创建复合索引
);


-- 方法二:修改表中的列为复合索引
create table tests_indexs2(
 id bigint primary key auto_increment,
 name varchar(20),
 sno varchar(10),
 class_id bigint
);
alter table tests_indexs2 add index (sno,class_id);


-- 方法三:单独创建索引并指定索引名
create table tests_indexs3(
 id bigint primary key auto_increment,
 name varchar(20),
 sno varchar(10),
 class_id bigint
);
create index index_sno_class_id on tests_indexs3 (sno,class_id);

mysql> show tables;
+----------------------+
| Tables_in_test_index |
+----------------------+
| test1_pri            |
| test1_unique         |
| test2_pri            |
| test2_unique         |
| test3_pri            |
| test3_unique         |
| test_index1          |
| test_index2          |
| test_index3          |
| tests_indexs1        |
| tests_indexs2        |
| tests_indexs3        |
+----------------------+
12 rows in set (0.00 sec)

mysql> desc tests_indexs1;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| id       | bigint      | NO   | PRI | NULL    | auto_increment |
| name     | varchar(20) | YES  |     | NULL    |                |
| sno      | varchar(10) | YES  | MUL | NULL    |                |
| class_id | bigint      | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

2.6 查看索引

查看索引语法:

复制代码
-- 方式一
show keys from table_name\G;

-- 方式二
show index from table_name;

-- 方式三,查看简要信息
desc table_name;

查看刚才创建的普通索引 test_index3:

复制代码
mysql> show index from test_index3\G
*************************** 1. row ***************************
        Table: test_index3
   Non_unique: 0
     Key_name: PRIMARY
 Seq_in_index: 1
  Column_name: id
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null:
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: NULL
*************************** 2. row ***************************
        Table: test_index3
   Non_unique: 0
     Key_name: name
 Seq_in_index: 1
  Column_name: name
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: NULL
*************************** 3. row ***************************
        Table: test_index3
   Non_unique: 1
     Key_name: index2_sno
 Seq_in_index: 1
  Column_name: sno
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: NULL
3 rows in set (0.00 sec)
-- 查出的row有几条就说明有几个索引

mysql> desc test_index3;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | bigint      | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  | UNI | NULL    |                |
| sno   | varchar(10) | YES  | MUL | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
-- 可以看到在test_index3表中有主键索引、唯一索引、普通索引

2.7 删除主键索引

删除主键索引时,不需要写索引名字因为表中只有一个主键,并且如果主键列是自增列,必须将自增的属性给取消再删除主键

删除主键索引语法:

复制代码
alter table 表名 drop primary key;

删除test1_pri 表中的主键索引:

复制代码
-- 直接删除则会报错
mysql> alter table test1_pri drop primary key;
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key

-- 先修改自增列再删除
mysql> alter table test1_pri modify id bigint;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table test1_pri drop primary key;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0


-- 查看
mysql> desc test1_pri;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | bigint      | NO   |     | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> show index from test1_pri;
Empty set (0.00 sec)

2.8 删除其他索引

删除其他索引与删除主键索引不同,删除其他索引需要加上索引的名字,删除其他索引语法:

复制代码
alter table 表名 drop index 索引名;

删除test_index2表中的普通索引:

复制代码
-- 删除
mysql> alter table test_index2 drop index index1_sno;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

-- 查看
mysql> desc test_index2;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | bigint      | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  | UNI | NULL    |                |
| sno   | varchar(10) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)


mysql> show index from test_index2\G
*************************** 1. row ***************************
        Table: test_index2
   Non_unique: 0
     Key_name: PRIMARY
 Seq_in_index: 1
  Column_name: id
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null:
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: NULL
*************************** 2. row ***************************
        Table: test_index2
   Non_unique: 0
     Key_name: name
 Seq_in_index: 1
  Column_name: name
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: NULL
2 rows in set (0.00 sec)
-- 此时就剩下主键索引和唯一索引了

2.9 创建索引的注意事项

  • 索引应该创建在高频查询的列上,如果有慢查询出现,无论是不是高频查询的列都要进行优化创建索引
  • 索引需要占用额外的存储空间,因为创建索引会单独维度一个索引树
  • 对表进行插入、更新、删除操作,都会修改索引树,可能会影响性能
  • 创建过多不合理的索引会导致性能下降

2.10 查看查询时是否使用索引

当我们查询时想要判断是不是使用了索引,不能单纯的执行的时间上判断,需要用执行计划来分析当前的查询是否走了索引,那么当我们在SQL语句的前面加上explain关键字就可以得到一个分析结果:

复制代码
-- 查看学生表中的索引信息
mysql> desc student;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| id       | bigint      | NO   | PRI | NULL    | auto_increment |
| name     | varchar(20) | YES  |     | NULL    |                |
| sno      | varchar(20) | YES  |     | NULL    |                |
| age      | int         | YES  |     | NULL    |                |
| gender   | char(1)     | YES  |     | NULL    |                |
| class_id | bigint      | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)


-- 查看学生表
mysql> select * from student;
+----+--------------+--------+------+--------+----------+
| id | name         | sno    | age  | gender | class_id |
+----+--------------+--------+------+--------+----------+
|  1 | 唐三藏       | 100001 |   18 | 男     |        1 |
|  2 | 孙悟空       | 100002 |   18 | 女     |        1 |
|  3 | 猪悟能       | 100003 |   18 | 男     |        1 |
|  4 | 沙悟净       | 100004 |   18 | 男     |        1 |
|  5 | 宋江         | 200001 |   18 | 女     |        2 |
|  6 | 武松         | 200002 |   18 | 男     |        2 |
|  7 | 李逹         | 200003 |   18 | 男     |        2 |
|  8 | 不想毕业     | 200004 |   18 | 女     |        2 |
+----+--------------+--------+------+--------+----------+
8 rows in set (0.00 sec)


-- 使用id主键索引查找孙悟空同学的信息
mysql> explain select *from student where id=2;
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | student | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL  |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.01 sec)




-- 使用name进行查询
mysql> explain select *from student where name='孙悟空';
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | student | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    8 |    12.50 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
--此时就没有用到索引

type列详解:

假设现在我有一个复合主键,查看复合主键进行查询:

复制代码
-- 创建名字和学号的复合主键
mysql> alter table student add index index_name_sno (name,sno);
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

-- 查看信息
mysql> desc student;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| id       | bigint      | NO   | PRI | NULL    | auto_increment |
| name     | varchar(20) | YES  | MUL | NULL    |                |
| sno      | varchar(20) | YES  |     | NULL    |                |
| age      | int         | YES  |     | NULL    |                |
| gender   | char(1)     | YES  |     | NULL    |                |
| class_id | bigint      | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)

-- 使用复合主键查询
mysql> explain select *from student where name='孙悟空' and sno='100002';
+----+-------------+---------+------------+------+----------------+----------------+---------+-------------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys  | key            | key_len | ref         | rows | filtered | Extra |
+----+-------------+---------+------------+------+----------------+----------------+---------+-------------+------+----------+-------+
|  1 | SIMPLE      | student | NULL       | ref  | index_name_sno | index_name_sno | 166     | const,const |    1 |   100.00 | NULL  |
+----+-------------+---------+------------+------+----------------+----------------+---------+-------------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
-- 可以看见使用的复合索引index_name_sno

那么复合主键的列单独进行查询还能不能使用到索引呢?

复制代码
-- 使用name进行查询
mysql> explain select *from student where name='孙悟空';
+----+-------------+---------+------------+------+----------------+----------------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys  | key            | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+------+----------------+----------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | student | NULL       | ref  | index_name_sno | index_name_sno | 83      | const |    1 |   100.00 | NULL  |
+----+-------------+---------+------------+------+----------------+----------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

-- 当前使用name进行查询索引是生效的


-- 使用sno进行查询:
mysql> explain select *from student where sno='100002';
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | student | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    8 |    12.50 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

-- 当前使用sno进行查询不生效

比如上面的拼音索引:

我们肯定需要先根据声母进行查询,在根据韵母进行查询,不能直接根据韵母就查询,这样的话就进行全表查询了

创建复合索引的注意事项:

创建索引时指定的列的顺序与索引排序有关,先针对第一个列进行排序,再针对后面的列进行排序


相关推荐
DBA小马哥3 小时前
Oracle迁移实战:如何轻松跨越异构数据库的学习与技术壁垒
数据库·学习·oracle·信创·国产化平替
无敌最俊朗@3 小时前
STL-vector面试剖析(面试复习4)
java·面试·职场和发展
暮乘白帝过重山4 小时前
ArkTS ForEach 参数解析:组件与键值生成器
开发语言·数据库
PPPPickup4 小时前
easychat项目复盘---获取联系人列表,联系人详细,删除拉黑联系人
java·前端·javascript
LiamTuc4 小时前
Java构造函数
java·开发语言
长安er4 小时前
LeetCode 206/92/25 链表翻转问题-“盒子-标签-纸条模型”
java·数据结构·算法·leetcode·链表·链表翻转
菜鸟plus+4 小时前
N+1查询
java·服务器·数据库
子夜江寒4 小时前
MySQL 表创建与数据导入导出
数据库·mysql
我要添砖java4 小时前
《JAVAEE》网络编程-什么是网络?
java·网络·java-ee
CoderYanger4 小时前
动态规划算法-01背包问题:50.分割等和子集
java·算法·leetcode·动态规划·1024程序员节