MySQL之索引
MySQL之索引和事务
- 一.索引
- 1.1索引的概念
- 1.2索引的原理
- 1.2.1B树和B+树
- 1.2.2聚簇索引和非聚簇索引
- 1.3索引的分类
- 1.4索引的使用
- 1.4.1创建索引
- 1.4.2查看索引
- 1.4.3删除索引
- 1.4.4使用索引
一.索引
1.1索引的概念
索引的官方定义是这样的:在关系数据库中,索引是一种单独的、物理的数对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。那么要如何理解索引呢?
在我们使用数据库时随着数据越来越多查找的速度会变得越来越慢这不利于我们的使用,为了解决这个问题程序员们创造了索引。我们可以把索引理解成一本书中的一个目录,在没有目录的时候我们想要找到特定的内容就只能一页页的去翻在有了目录后我们就可以直接跳转到特定的页上。那么我们就来看看索引是不是真的可以加快查找的速度。
//插入80万条记录
mysql> call insert_user(1, 8000000);
Query OK, 0 rows affected (9 min 46.71 sec)//不使用索引查找
mysql> select * from test_user where id_number=556677;
+-----------+----------------+------+---------------------+
| id_number | name | age | create_time |
+-----------+----------------+------+---------------------+
| 556677 | Qduma Hmmbuunf | 61 | 2025-06-06 14:54:47 |
+-----------+----------------+------+---------------------+
1 row in set (2.69 sec)//耗时mysql> select * from test_user where id_number=556677;
+-----------+----------------+------+---------------------+
| id_number | name | age | create_time |
+-----------+----------------+------+---------------------+
| 556677 | Qduma Hmmbuunf | 61 | 2025-06-06 14:54:47 |
+-----------+----------------+------+---------------------+
1 row in set (2.62 sec)//创建id_number的索引
mysql> create index idx_test_user_id_number on test_user(id_number);
Query OK, 0 rows affected (14.71 sec)
Records: 0 Duplicates: 0 Warnings: 0//使用索引查找
mysql> select * from test_user where id_number=556677;
+-----------+----------------+------+---------------------+
| id_number | name | age | create_time |
+-----------+----------------+------+---------------------+
| 556677 | Qduma Hmmbuunf | 61 | 2025-06-06 14:54:47 |
+-----------+----------------+------+---------------------+
1 row in set (0.00 sec)//耗时
1.2索引的原理
而在MySQL中由于需要大量的进行磁盘和内存之间的交互也就是进行IO但是IO是非常消耗性能的那么想要提高性能就必须降低IO的次数。对于操纵系统来说降低IO次数也是必须所以操作系统自己就进行了优化也就是增大IO时读取的数据从而提高读取到有效数据的概率,这种方法同样遵循了计算机的局部性原理,这个原理提出了当计算机访问一个地址的数据的时候,与其相邻的数据也会很快被访问到。所以我们将MySQL中读取一次的数据叫做一页,不同的操作系统对于页的大小也是不同的。这是操作系统自己做出的优化而索引的产生也是用来降低IO的次数但是存储引擎也有着自己的处理方法也就是在底层构建索引时使用不同的数据结构。
操作系统是通过增大读取数据的大小来减少IO次数而索引的作用就是通过排除错误的数据来减少IO次数有点类似于二分查找,每次查找时都会去除一半的错误答案。那么想要完成这点我们就需要利用一个数据结构B+树。
1.2.1B树和B+树
想要了解B+树我们就需要先了解它的原型体B树以及为什么大部分存储引擎是使用B+树而不是B树。
B树全称平衡多路查找树,它的结构是这样的
我们可以发现B树的特点是:
- 树内的每个节点都能存储数据
- 叶子节点之间无指针结构
接下来是B+树的结构
B+树的特点是:
- 只有叶子节点能存储数据
- 叶子节点之间有指针结构
所以对于B树来说每个节点都是KV结构但是对于B+树来说只有叶子节点才是KV结构
那么为什么是使用B+树而不是B树呢那么我需要先从索引具体是如何实现减少IO次数的来说了,在不适用索引时对于大量的数据我们想要查找到具体的内容我们需要对这些数据进行遍历来查找所以IO的次数会很多但是在使用了索引后我们可以通过索引来指向具体的数据,就像书中的目录一样目录越多查找的难度就越低如果对于一本书里的每一个字都有目录那么查找的难道就大大降低了。
而无论是B树还是B+树都是将key作为目录value作为数据所以key的数量越多那么查找value的速度就越快。所以这就是为什么要选择B+树而不是B树因为B树的每个节点都是KV结构所以key的数量有一部分被变成了value而B+树只有叶子节点才有KV结构所以key的数量就更多查找的速度也就更快。
并且由于局部性原理很有可能读取一个数据后再读取它相邻的数据但是对于B树来说我们每次读取数据都需要从头再次查找而B+树我们可以利用叶子节点之间的指针来查找相邻的数据。这也就加快了速度。
注意:不同的存储引擎对于数据结构的选择是不一样的大部分都是选择B+树少部分选择是B树也有个例引擎选择的是hash。
1.2.2聚簇索引和非聚簇索引
在了解了实现索引的数据结构之后我们知道使用索引其实就是将数据库中的数据构造一个B+树出来(大部分的),但是对于数据的存储方式不同索引的类型也不同我们将其分为聚簇索引和非聚簇索引。这里我们的存储引擎默认为InnoDB。
- 聚簇索引
聚簇索引也叫做主键索引,如果一个表中有主键那么默认就会选择主键生成索引如果没有主键那么就会选择一个唯一的非空键为聚簇索引,如果也没有这样的键那么存储引擎就会隐式定义一个主键来作为聚簇索引。由于聚簇索引是使用唯一并且带有顺序的键来构建索引所以导致表的物理存储顺序也会根据这个键值得顺序来存储,简单来说聚簇索引决定了表的物理存储顺序。而聚簇索引在存储方面的表现是对于B+树中的叶子节点会在value中存储完整的数据行,所以当我们使用聚簇索引查找数据时可以直接找到具体的内容。 - 非聚簇索引
非聚簇索引也被叫做辅助索引或者二级索引,它可以使用任何列生成索引不必局限于主键。并且非聚簇索引存储数据时是将主键值作为value存储的,也就是说索引和数据是分开存储的通过非聚簇索引查找数据时需要先找到对应的主键值再通过主键值构成的聚簇索引找到具体的数据,这就是回表查询也叫做二次查询。这也就导致了有时非聚簇索引查找数据时效率不如聚簇索引。
对于这两种索引一般情况下聚簇索引的查找速度是高于非聚簇索引的并且对于范围查询时由于非聚簇索引需要进行回表查询导致范围查询时速度就更不如聚簇索引了,但是非聚簇索引的优势是当表发生频繁的插入删除时由于聚簇索引决定了表的物理存储顺序所以会影响它频繁发生变化,而非聚簇索引是将主键值作为指针所以只要主键值不变那么非聚簇索引的B+树就不会发生变化也就减少了维护的成本。
1.3索引的分类
索引一样有着不同的种类,一般可以我们可以从存储引擎和逻辑上分别进行分类,从存储引擎上将其分为聚簇索引和非聚簇索引这部分我们在索引的原理上会提到。现在我们先用逻辑上进行分类,从逻辑上索引被分为普通索引,唯一索引,主键索引,全文索引。同样我们以InnoDB为例。
- 普通索引
普通索引是MySQL中最基础的索引,没有任何的限制可以在任意可以定义索引的列上创建,并且普通索引允许列中存在空值和重复值。普通索引的作用就是最基础的加快对数据的查找速度 - 唯一索引
唯一索引相对于普通索引它的作用不是加快查找速度而是防止数据存在重复所以它只能在唯一键 上创建并且也允许其中存在空值。想要创建唯一索引我们一般使用的unique关键字。 - 主键索引
主键索引在唯一索引的基础上规定了列值不允许为空所以它一般是使用在主键上的,想要创建主键索引我们需要使用primary key关键字。 - 全文索引
全文索引主要用来查找文本中的关键字,只能在 CHAR、VARCHAR 或 TEXT 类型的列上创建。在 MySQL 中只有 MyISAM 存储引擎支持全文索引。全文索引允许在索引列中插入重复值和空值。 - 组合索引
一般使用创建索引时我们是单列创建但是索引也可以使用多列进行创建,我们可以利用表中的多列创建一个组合索引。但是在使用多列创建了组合索引后只有查询条件中使用了这些字段中第一个字段时,索引才会被使用。
组合索引的使用会再次加快查找的速度这是因为使用组合索引实际上我们是先创建了多个索引再使用多个索引来查找数据相对于使用单列索引也就是一个索引进行查找当然会更加快。
1.4索引的使用
接下来就是索引的使用,我们会介绍怎么增删查改普通索引,唯一索引,主键索引以及组合索引。
1.4.1创建索引
想要创建一个索引有两种方法分别是自动创建和手动创建,其中自动创建是指当我们为表中增加主键,唯一键和外键时MySQL会自动使用对应列创建一个索引。
手动创建就需要我们自己使用SQL来指明对应列创建索引了
- 主键索引
//1.创建表时创建主键
mysql> create table test1(-> id int primary key auto_increment,-> name varchar(20)-> );
Query OK, 0 rows affected (0.01 sec)mysql> show keys from test1\G;
*************************** 1. row ***************************Table: test1Non_unique: 0Key_name: PRIMARYSeq_in_index: 1Column_name: idCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: Index_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
1 row in set (0.00 sec)ERROR:
No query specified//2.创建表时指明某列为主键
mysql> create table test2(-> id int,-> name varchar(20),-> primary key(id)-> );
Query OK, 0 rows affected (0.01 sec)mysql> show keys from test2\G;
*************************** 1. row ***************************Table: test2Non_unique: 0Key_name: PRIMARYSeq_in_index: 1Column_name: idCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: Index_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
1 row in set (0.01 sec)ERROR:
No query specified//3.创建表后将某列修改为主键
mysql> create table test3(-> id int,-> name varchar(20)-> );
Query OK, 0 rows affected (0.01 sec)mysql> alter table test3 add primary key(id);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> show keys from test3\G;
*************************** 1. row ***************************Table: test3Non_unique: 0Key_name: PRIMARYSeq_in_index: 1Column_name: idCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: Index_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
1 row in set (0.00 sec)
- 唯一索引
//1.创建表时创建唯一键
mysql> create table test4(-> id int primary key auto_increment,-> name varchar(20) unique-> );
Query OK, 0 rows affected (0.01 sec)mysql> show keys from test4\G;
*************************** 1. row ***************************Table: test4Non_unique: 0Key_name: PRIMARYSeq_in_index: 1Column_name: idCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: Index_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
*************************** 2. row ***************************Table: test4Non_unique: 0Key_name: nameSeq_in_index: 1Column_name: nameCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
2 rows in set (0.00 sec)ERROR:
No query specified//2.创建表时指明某列为唯一键
mysql> create table test5(-> id int primary key auto_increment,-> name varchar(20),-> unique(name)-> );
Query OK, 0 rows affected (0.01 sec)mysql> show keys from test5\G;
*************************** 1. row ***************************Table: test5Non_unique: 0Key_name: PRIMARYSeq_in_index: 1Column_name: idCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: Index_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
*************************** 2. row ***************************Table: test5Non_unique: 0Key_name: nameSeq_in_index: 1Column_name: nameCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
2 rows in set (0.01 sec)ERROR:
No query specified//创建表后修改某列为唯一键
mysql> create table test6(-> id int,-> name varchar(20)-> );
Query OK, 0 rows affected (0.01 sec)mysql> alter table test6 add unique(name);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> show keys from test6\G;
*************************** 1. row ***************************Table: test6Non_unique: 0Key_name: nameSeq_in_index: 1Column_name: nameCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
1 row in set (0.00 sec)ERROR:
No query specified
- 普通索引
//1.创建表指定索引列
mysql> create table test7(-> id int primary key auto_increment,-> name varchar(20) unique,-> age int,-> index(age)-> );
Query OK, 0 rows affected (0.02 sec)mysql> show keys from test7\G;
*************************** 1. row ***************************Table: test7Non_unique: 0Key_name: PRIMARYSeq_in_index: 1Column_name: idCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: Index_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
*************************** 2. row ***************************Table: test7Non_unique: 0Key_name: nameSeq_in_index: 1Column_name: nameCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
*************************** 3. row ***************************Table: test7Non_unique: 1Key_name: ageSeq_in_index: 1Column_name: ageCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
3 rows in set (0.00 sec)ERROR:
No query specified//2.修改表中的某列为普通索引
mysql> create table test8(-> id int,-> name varchar(20),-> age int-> );
Query OK, 0 rows affected (0.01 sec)mysql> alter table test8 add index(age);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> show keys from test8\G;
*************************** 1. row ***************************Table: test8Non_unique: 1Key_name: ageSeq_in_index: 1Column_name: ageCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
1 row in set (0.00 sec)ERROR:
No query specified//3.单独创建索引并指定索引名
mysql> create table test9(-> id int,-> name varchar(20),-> age int-> );
Query OK, 0 rows affected (0.02 sec)mysql> show keys from test9\G;
Empty set (0.00 sec)ERROR:
No query specifiedmysql> create index myindex on test9(age);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> show keys from test9\G;
*************************** 1. row ***************************Table: test9Non_unique: 1Key_name: myindexSeq_in_index: 1Column_name: ageCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
1 row in set (0.00 sec)ERROR:
No query specified
- 组合索引
//1.修改表中的列为复合索引
mysql> create table test10(-> id int,-> name varchar(20),-> age int,-> sno varchar(10)-> );
Query OK, 0 rows affected (0.01 sec)mysql> alter table test10 add index(age,sno);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> show keys from test10\G;
*************************** 1. row ***************************Table: test10Non_unique: 1Key_name: ageSeq_in_index: 1Column_name: ageCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
*************************** 2. row ***************************Table: test10Non_unique: 1Key_name: ageSeq_in_index: 2Column_name: snoCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
2 rows in set (0.00 sec)ERROR:
No query specified//2.创建表时指定索引列
mysql> create table test11(-> id int,-> name varchar(20),-> age int,-> sno varchar(10),-> index (age,sno)-> );
Query OK, 0 rows affected (0.02 sec)mysql> show keys from test11\G;
*************************** 1. row ***************************Table: test11Non_unique: 1Key_name: ageSeq_in_index: 1Column_name: ageCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
*************************** 2. row ***************************Table: test11Non_unique: 1Key_name: ageSeq_in_index: 2Column_name: snoCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
2 rows in set (0.00 sec)ERROR:
No query specified//3.单独创建索引并指定索引名
mysql> create table test12(-> id int,-> name varchar(20),-> age int,-> sno varchar(10)-> );
Query OK, 0 rows affected (0.01 sec)mysql> create index joindex on test12(age,sno);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> show keys from test12\G;
*************************** 1. row ***************************Table: test12Non_unique: 1Key_name: joindexSeq_in_index: 1Column_name: ageCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
*************************** 2. row ***************************Table: test12Non_unique: 1Key_name: joindexSeq_in_index: 2Column_name: snoCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
2 rows in set (0.00 sec)ERROR:
No query specified
1.4.2查看索引
查询所有的SQL指令很简单,在上面创建索引时我也演示过了
//1.查看一个表中的全部索引
mysql> show keys from test12\G;
*************************** 1. row ***************************Table: test12Non_unique: 1Key_name: joindexSeq_in_index: 1Column_name: ageCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
*************************** 2. row ***************************Table: test12Non_unique: 1Key_name: joindexSeq_in_index: 2Column_name: snoCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
2 rows in set (0.00 sec)//2.查看一个表中的所有索引
mysql> show index from test12\G;
*************************** 1. row ***************************Table: test12Non_unique: 1Key_name: joindexSeq_in_index: 1Column_name: ageCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
*************************** 2. row ***************************Table: test12Non_unique: 1Key_name: joindexSeq_in_index: 2Column_name: snoCollation: ACardinality: 0Sub_part: NULLPacked: NULLNull: YESIndex_type: BTREEComment:
Index_comment: Visible: YESExpression: NULL
2 rows in set (0.00 sec)ERROR:
No query specified//3.查看索引的大致信息
mysql> desc test7;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | UNI | NULL | |
| age | int | YES | MUL | NULL | |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
1.4.3删除索引
这几种索引的删除方式都大差不大我们就直接举例即可
//1.删除主键索引
mysql> desc test1;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)//删除主键索引时如果主键索引有自增属性就需要先删除自增属性
mysql> alter table test1 drop primary key;
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a keymysql> alter table test1 modify id int;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> alter table test1 drop primary key;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> desc test1;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)//2.删除其他索引
mysql> desc test4;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | UNI | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)mysql> alter table test4 drop index name;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> desc test4;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
1.4.4使用索引
当我们为某列创建索引后我们查找数据就会自动使用索引,所以索引的使用没有什么可说的但是对于复合索引我们需要注意一个问题:最左匹配原则。这个原则规定了在使用复合索引时第一个列必须出现在查找语句中才会使用到复合索引。
当我们使用三个列创建一个复合索引(id,name,age)时我们实际上是创建了三个索引分别是(id),(id,name),(id,name,age)。
mysql> create table test13( id int, name varchar(20), age int, index(id,name,age) );
Query OK, 0 rows affected (0.01 sec)mysql> show keys from test13;
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| test13 | 1 | id | 1 | id | A | 0 | NULL | NULL | YES | BTREE | | | YES | NULL |
| test13 | 1 | id | 2 | name | A | 0 | NULL | NULL | YES | BTREE | | | YES | NULL |
| test13 | 1 | id | 3 | age | A | 0 | NULL | NULL | YES | BTREE | | | YES | NULL |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
3 rows in set (0.00 sec)mysql> desc test13;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | YES | MUL | NULL | |
| name | varchar(20) | YES | | NULL | |
| age | int | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
从这两个信息中我们可以发现第一列id是这个复合索引的主体,在查看表结构时复合索引是属于id列的并且它在索引中的顺序也是1。所以在我们使用索引进行查找数据时就必须带上id列不然就无法使用复合索引。
//可以使用复合索引
select * from test13 where id = 12;
select * from test13 where id = 1 and name = '张三' and age = 18;
select * from test13 where id = 2 and name = '张三';
select * from test13 where id = 3 and age = 18;
select * from test13 where age = 18 and name = '张三' and id = 1;//不能使用复合索引
select * from test13 where name = '张三';
select * from test13 where name = '张三' and age = 18;