1.索引概述及其优缺点

1.1索引概述

MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。
索引的本质:索引是数据结构。你可以简单理解为“排好序的快速查找数据结构”,满足特定查找算法。
这些数据结构以某种方式指向数据, 这样就可以在这些数据结构的基础上实现 高级查找算法 。

注:本文主要说的是MySQL57版本

1.2为什么使用索引

Snipaste_2023-08-04_15-47-04

假如给数据使用 二叉树 这样的数据结构进行存储,如下图所示

Snipaste_2023-08-04_15-48-18

索引的作用:能以更少的查询次数来找到数据,减少与磁盘的IO交互次数,更快地查找到数据

1.3优点

(1)类似大学图书馆建书目索引,提高数据检索的效率,降低 数据库的IO成本 ,这也是创建索引最主
要的原因。

(2)通过创建唯一索引,可以保证数据库表中每一行 数据的唯一性

(3)在实现数据的参考完整性方面,可以 加速表和表之间的连接 。换句话说,对于有依赖关系的子表和父表联合查询时,
可以提高查询速度

(4)在使用分组和排序子句进行数据查询时,可以显著减少查询中分组和排序的时间 ,降低了CPU的消耗。

1.4缺点

增加索引也有许多不利的方面,主要表现在如下几个方面: (1)创建索引和维护索引要 耗费时间 ,并 且随着数据量的增加,所耗费的时间也会增加。

(2)索引需要占磁盘空间 ,除了数据表占数据空间之 外,每一个索引还要占一定的物理空间, 存储在磁盘上 ,如果有大量的索引,索引文件就可能比数据文 件更快达到最大文件尺寸。 (3)虽然索引大大提高了查询速度,同时却会 降低更新表的速度 。当对表中的数据进行增加、删除和修改的时候,索引也要动态地维护,这样就降低了数据的维护速度。 因此,选择使用索引时,需要综合考虑索引的优点和缺点。

(所以一般都是先删了索引,进行增删改之后再重新建索引)

2.MySQL的三层逻辑架构

Snipaste_2023-08-04_15-57-30

Snipaste_2023-08-02_21-46-14

简述一下:

  1. 连接层:客户端和服务器端建立连接,客户端发送 SQL 至服务器端;

  2. 服务层(SQL层):SQL接口、解析器、查询优化器、查询缓存组件(8.0版本被删掉了)

    对 SQL 语句进行查询处理;与数据库文件的存储方式无关;

  3. 存储引擎层:与数据库文件打交道,负责数据的存储和读取。

3.MySQL存储引擎

3.1存储引擎概述

存储引擎是数据库底层的组件,是数据库的核心。 使用存储引擎可以创建、查询、更新、删除数据库。存储引擎可以理解为数据库的操作系统,不同的存储引擎提供的存储方式、索引机制等也不相同,就像 Windows 系统和 Mac 系统一样。在数据库开发时,为了提高 MySQL 的灵活性和高效性,可以根据实际情况来选择存储引擎。

3.2查看mysql提供什么存储引擎:

1
show engines;

Snipaste_2023-08-04_16-04-31

可以看见,MySQL57默认用的是InnoDB(5.5之后就一直如此)

3.设置系统默认的存储引擎

如果在创建表的语句中没有显式指定表的存储引擎的话,那就会默认使用 InnoDB 作为表的存储引擎。
如果我们想改变表的默认存储引擎的话,可以这样写启动服务器的命令行:

1
SET DEFAULT_STORAGE_ENGINE=MyISAM;

或者修改 my.cnf 文件:

1
2
3
default-storage-engine=MyISAM
# 重启服务
systemctl restart mysqld.service

4.设置表的存储引擎

存储引擎是负责对表中的数据进行提取和写入工作的,我们可以为 不同的表设置不同的存储引擎 ,也就是
说不同的表可以有不同的物理存储结构,不同的提取和写入方式。

4.1创建表时指定存储引擎

1
2
3
CREATE TABLE 表名(
建表语句;
) ENGINE = 存储引擎名称;

4.2修改表的存储引擎

1
ALTER TABLE 表名 ENGINE = 存储引擎名称;

比如我们修改一下 engine_demo_table 表的存储引擎:

1
ALTER TABLE engine_demo_table ENGINE = InnoDB;

5.MyISAM和InnoDB

5.1哪个好?—–InnoDB

除非有非常特别的原因需要使用其他的存储引擎,否则应该优先考虑InnoDB引擎。

MySQL5.5之前的默认存储引擎是MyISAM,5.5之后改为了InnoDB。

对比项 MyISAM InnoDB
默认安装 Y Y
默认使用 N Y
外键 不支持 支持
事务 不支持 支持
关注点 性能:节省资源、消耗少、简单业 务 事务:并发写、事务、更大资源
缓存 只缓存索引,不缓存真实数据 不仅缓存索引还要缓存真实数据,
对内存要求较 高,
而且内存大小对性能有决定性的影响
自带系 统表使 用 Y N
行表锁 表锁,即使操作一条记录也会锁住 整个表,不适合高并发的操作 行锁,操作时只锁某一行,不对其它行有影响, 适合高并发的操作

对比MyISAM的存储引擎, InnoDB写的处理效率差一些 ,并且会占用更多的磁盘空间以保存数据和索引。

5.2阿里巴巴、淘宝用哪个Snipaste_2023-08-04_16-29-29

  • Percona 为 MySQL 数据库服务器进行了改进,在功能和性能上较 MySQL 有很显著的提升。
  • 该版本提升了在高负载情况下的 InnoDB 的性能、为 DBA 提供一些非常有用的性能诊断工具;另外 有更多的参数和命令来控制服务器行为。
  • 该公司新建了一款存储引擎叫 Xtradb 完全可以替代 Innodb ,并且在性能和并发上做得更好
  • 阿里巴巴大部分mysql数据库其实使用的percona的原型加以修改。

5.3InnoDB中的索引方案 B+树(重要)

建一个表:

1
2
3
4
5
6
mysql> CREATE TABLE index_demo(
-> c1 INT,
-> c2 INT,
-> c3 CHAR(1),
-> PRIMARY KEY(c1)
-> ) ROW_FORMAT = Compact;

这个新建的 index_demo 表中有2个INT类型的列,1个CHAR(1)类型的列,而且我们规定了c1列为主键,
这个表使用 Compact 行格式来实际存储记录的。这里我们简化了index_demo表的行格式示意图:

Snipaste_2023-08-04_16-41-21

把一些记录放到页里的示意图就是:

Snipaste_2023-08-04_16-41-58

(此处略过其他迭代过程)

迭代3次:目录项记录页的目录页:

Snipaste_2023-08-04_16-44-22

如图,我们生成了一个存储更高级目录项的 页33 ,这个页中的两条记录分别代表页30和页32,如果用户记录的主键值在 [1, 320) 之间,则到页30中查找更详细的目录项记录,如果主键值 不小于320 的话,就到页32中查找更详细的目录项记录。

我们可以用下边这个图来描述它:

Snipaste_2023-08-04_16-46-32

这个数据结构,它的名称是 B+树

一个B+树的节点其实可以分成好多层,规定最下边的那层,也就是存放我们用户记录的那层为第 0 层,之后依次往上加。之前我们做了一个非常极端的假设:存放用户记录的页 最多存放3条记录 ,存放目录项记录的页 最多存放4条记录 。其实真实环境中一个页存放的记录数量是非常大的,假设所有存放用户记录的叶子节点代表的数据页可以存放 100条用户记录 ,所有存放目录项记录的内节点代表的数据页可以存放 1000条目录项记录 ,那么:

  • 如果B+树只有1层,也就是只有1个用于存放用户记录的节点,最多能存放 100 条记录。

  • 如果B+树有2层,最多能存放 1000×100=10,0000 条记录。

  • 如果B+树有3层,最多能存放 1000×1000×100=1,0000,0000 条记录。

  • 如果B+树有4层,最多能存放 1000×1000×1000×100=1000,0000,0000 条记录。相当多的记 录!!!

你的表里能存放 100000000000 条记录吗?所以一般情况下,我们 用到的B+树都不会超过4层 ,那我们通过主键值去查找某条记录最多只需要做4个页面内的查找(查找3个目录项页和一个用户记录页),又因为在每个页面内有所谓的 **Page Directory(页目录),所以在页面内也可以通过 二分法 实现快速定位记录。

6.索引的创建与设计原则

6.1索引的声明与使用

6.1.1索引的分类

MySQL的索引包括普通索引、唯一性索引、全文索引、单列索引、多列索引和空间索引等。

  • 功能逻辑 上说,索引主要有 4 种,分别是普通索引、唯一索引、主键索引、全文索引。
  • 按照 物理实现方式 ,索引可以分为 2 种:聚簇索引和非聚簇索引。
  • 按照 作用字段个数 进行划分,分成单列索引和联合索引

6.1.2创建索引

1.创建表的时候创建索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 01-索引的创建

#第1种:CREATE TABLE

#隐式的方式创建索引。在声明有主键约束、唯一性约束、外键约束的字段上,会自动的添加相关的索引
CREATE DATABASE dbtest2;

USE dbtest2;

CREATE TABLE dept(
dept_id INT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(20)
);

CREATE TABLE emp(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(20) UNIQUE,
dept_id INT,
CONSTRAINT emp_dept_id_fk FOREIGN KEY(dept_id) REFERENCES dept(dept_id)
);

但是,如果显式创建表时创建索引的话,基本语法格式如下:

1
2
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 为同义词,两者的作用相同,用来指定创建索引;
  • index_name 指定索引的名称,为可选参数,如果不指定,那么MySQL默认col_name为索引名;
  • col_name 为需要创建索引的字段列,该列必须从数据表中定义的多个列中选择;
  • length 为可选参数,表示索引的长度,只有字符串类型的字段才能指定索引长度;
  • ASC 或 DESC 指定升序或者降序的索引值存储。

1.创建普通索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#显式的方式创建:
#① 创建普通的索引
CREATE TABLE book(
book_id INT ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR,
#声明索引
INDEX idx_bname(book_name)
);

#通过命令查看索引
#方式1
SHOW CREATE TABLE book;

#方式2
SHOW INDEX FROM book;


ALTER TABLE `book` CHARSET=utf8;

ALTER TABLE `book` CONVERT TO CHARACTER SET utf8;

#性能分析工具:EXPLAIN
EXPLAIN SELECT * FROM book WHERE book_name = 'mysql高级';

2.创建唯一索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#② 创建唯一索引
# 声明有唯一索引的字段,在添加数据时,要保证唯一性,但是可以添加null
CREATE TABLE book1(
book_id INT ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR,
#声明索引
UNIQUE INDEX uk_idx_cmt(COMMENT)
);

SHOW INDEX FROM book1;

ALTER TABLE `book1` CONVERT TO CHARACTER SET utf8;

INSERT INTO book1(book_id,book_name,COMMENT)
VALUES(1,'Mysql高级','适合有数据库开发经验的人员学习');

INSERT INTO book1(book_id,book_name,COMMENT)
VALUES(2,'Mysql高级',NULL);

SELECT * FROM book1;

3.主键索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#③ 主键索引
#通过定义主键约束的方式定义主键索引
CREATE TABLE book2(
book_id INT PRIMARY KEY ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR
);

SHOW INDEX FROM book2;

#通过删除主键约束的方式删除主键索引
ALTER TABLE book2
DROP PRIMARY KEY;

4.创建单列索引

1
2
3
4
5
6
7
8
9
10
11
12
13
#④ 创建单列索引
CREATE TABLE book3(
book_id INT ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR,
#声明索引
UNIQUE INDEX idx_bname(book_name)
);

SHOW INDEX FROM book3;

5.创建联合索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#⑤ 创建联合索引
CREATE TABLE book4(
book_id INT ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR,
#声明索引
INDEX mul_bid_bname_info(book_id,book_name,info)
);

SHOW INDEX FROM book4;

#分析
EXPLAIN SELECT * FROM book4 WHERE book_id = 1001 AND book_name = 'mysql';

EXPLAIN SELECT * FROM book4 WHERE book_name = 'mysql';

6.创建全文索引

1
2
3
4
5
6
7
8
9
10
#⑥ 创建全文索引
CREATE TABLE test4(
id INT NOT NULL,
NAME CHAR(30) NOT NULL,
age INT NOT NULL,
info VARCHAR(255),
FULLTEXT INDEX futxt_idx_info(info(50))
)

SHOW INDEX FROM test4;

7.创建空间索引

空间索引创建中,要求空间类型的字段必须为 非空 。 举例:创建表test5,在空间类型为GEOMETRY的字段上创建空间索引,SQL语句如下:

1
2
3
4
CREATE TABLE test5(
geo GEOMETRY NOT NULL,
SPATIAL INDEX spa_idx_geo(geo)
) ENGINE=MyISAM;

2.在已经存在的表上创建索引

ALTER TABLE … ADD …

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#第2种:表已经创建成功

#① ALTER TABLE ... ADD ...

CREATE TABLE book5(
book_id INT ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR
);

SHOW INDEX FROM book5;

ALTER TABLE book5 ADD INDEX idx_cmt(COMMENT);

ALTER TABLE book5 ADD UNIQUE uk_idx_bname(book_name);

ALTER TABLE book5 ADD INDEX mul_bid_bname_info(book_id,book_name,info);

CREATE INDEX … ON …

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#② CREATE INDEX ... ON ...

CREATE TABLE book6(
book_id INT ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR
);

SHOW INDEX FROM book6;

CREATE INDEX idx_cmt ON book6(COMMENT);

CREATE UNIQUE INDEX uk_idx_bname ON book6(book_name);

CREATE INDEX mul_bid_bname_info ON book6(book_id,book_name,info);

6.1.3删除索引

方式1:ALTER TABLE …. DROP INDEX ….

1
2
3
4
5
6
7
# 02-索引的删除

SHOW INDEX FROM book5;

#方式1ALTER TABLE .... DROP INDEX ....
ALTER TABLE book5
DROP INDEX idx_cmt;

方式2:DROP INDEX … ON …

1
2
#方式2DROP INDEX ... ON ...
DROP INDEX uk_idx_bname ON book5;

测试

1
2
3
4
5
6
7
8
9
10
#测试:删除联合索引中的相关字段,索引的变化
ALTER TABLE book5
DROP COLUMN book_name;

ALTER TABLE book5
DROP COLUMN book_id;

ALTER TABLE book5
DROP COLUMN info;
SHOW ENGINES;

7.索引的设计原则

7.1使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#04-索引的设计原则

#1. 数据的准备

CREATE DATABASE atguigudb1;

USE atguigudb1;

#1.创建学生表和课程表
CREATE TABLE `student_info` (
`id` INT(11) AUTO_INCREMENT,
`student_id` INT NOT NULL ,
`name` VARCHAR(20) DEFAULT NULL,
`course_id` INT NOT NULL ,
`class_id` INT(11) DEFAULT NULL,
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE `course` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`course_id` INT NOT NULL ,
`course_name` VARCHAR(40) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;


#函数1:创建随机产生字符串函数

DELIMITER //
CREATE FUNCTION rand_string(n INT)
RETURNS VARCHAR(255) #该函数会返回一个字符串
BEGIN
DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
DECLARE return_str VARCHAR(255) DEFAULT '';
DECLARE i INT DEFAULT 0;
WHILE i < n DO
SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));
SET i = i + 1;
END WHILE;
RETURN return_str;
END //
DELIMITER ;

SELECT @@log_bin_trust_function_creators;

SET GLOBAL log_bin_trust_function_creators = 1;


#函数2:创建随机数函数
DELIMITER //
CREATE FUNCTION rand_num (from_num INT ,to_num INT) RETURNS INT(11)
BEGIN
DECLARE i INT DEFAULT 0;
SET i = FLOOR(from_num +RAND()*(to_num - from_num+1)) ;
RETURN i;
END //
DELIMITER ;

# 存储过程1:创建插入课程表存储过程
DELIMITER //
CREATE PROCEDURE insert_course( max_num INT )
BEGIN
DECLARE i INT DEFAULT 0;
SET autocommit = 0; #设置手动提交事务
REPEAT #循环
SET i = i + 1; #赋值
INSERT INTO course (course_id, course_name ) VALUES (rand_num(10000,10100),rand_string(6));
UNTIL i = max_num
END REPEAT;
COMMIT; #提交事务
END //
DELIMITER ;


# 存储过程2:创建插入学生信息表存储过程
DELIMITER //
CREATE PROCEDURE insert_stu( max_num INT )
BEGIN
DECLARE i INT DEFAULT 0;
SET autocommit = 0; #设置手动提交事务
REPEAT #循环
SET i = i + 1; #赋值
INSERT INTO student_info (course_id, class_id ,student_id ,NAME ) VALUES (rand_num(10000,10100),rand_num(10000,10200),rand_num(1,200000),rand_string(6));
UNTIL i = max_num
END REPEAT;
COMMIT; #提交事务
END //
DELIMITER ;

#调用存储过程:
CALL insert_course(100);

SELECT COUNT(*) FROM course;

CALL insert_stu(1000000);

SELECT COUNT(*) FROM student_info;

#2. 哪些情况适合创建索引
#① 字段的数值有唯一性的限制
#② 频繁作为 WHERE 查询条件的字段
#查看当前stduent_info表中的索引
SHOW INDEX FROM student_info;
#student_id字段上没有索引的:
SELECT course_id, class_id, NAME, create_time, student_id
FROM student_info
WHERE student_id = 123110; #276ms

#给student_id字段添加索引
ALTER TABLE student_info
ADD INDEX idx_sid(student_id);

#student_id字段上有索引的:
SELECT course_id, class_id, NAME, create_time, student_id
FROM student_info
WHERE student_id = 123110; #43ms

#③ 经常 GROUP BYORDER BY 的列

#student_id字段上有索引的:
SELECT student_id, COUNT(*) AS num
FROM student_info
GROUP BY student_id LIMIT 100; #41ms

#删除idx_sid索引
DROP INDEX idx_sid ON student_info;


#student_id字段上没有索引的:
SELECT student_id, COUNT(*) AS num
FROM student_info
GROUP BY student_id LIMIT 100; #866ms

#再测试:
SHOW INDEX FROM student_info;

#添加单列索引
ALTER TABLE student_info
ADD INDEX idx_sid(student_id);

ALTER TABLE student_info
ADD INDEX idx_cre_time(create_time);


SELECT student_id, COUNT(*) AS num FROM student_info
GROUP BY student_id
ORDER BY create_time DESC
LIMIT 100; #5.212s

#修改sql_mode

SELECT @@sql_mode;

SET @@sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';

#添加联合索引
ALTER TABLE student_info
ADD INDEX idx_sid_cre_time(student_id,create_time DESC);

SELECT student_id, COUNT(*) AS num FROM student_info
GROUP BY student_id
ORDER BY create_time DESC
LIMIT 100; #0.257s

#再进一步:
ALTER TABLE student_info
ADD INDEX idx_cre_time_sid(create_time DESC,student_id);

DROP INDEX idx_sid_cre_time ON student_info;


#会使用idx_sid单列索引而不会使用idx_cre_time_sid索引
SELECT student_id, COUNT(*) AS num FROM student_info
GROUP BY student_id
ORDER BY create_time DESC
LIMIT 100; #3.790s
# 总结:创建联合索引的时候,先写GROUP BY字段的,后写ORDER BY字段的

#④ UPDATEDELETEWHERE 条件列
SHOW INDEX FROM student_info;


UPDATE student_info SET student_id = 10002
WHERE NAME = '462eed7ac6e791292a79'; #0.633s

#添加索引
ALTER TABLE student_info
ADD INDEX idx_name(NAME);


UPDATE student_info SET student_id = 10001
WHERE NAME = '462eed7ac6e791292a79'; #0.001s

# ⑤ DISTINCT 字段需要创建索引

# ⑥ #### 多表 JOIN 连接操作时,创建索引注意事项

#首先,`连接表的数量尽量不要超过 3 张`,因为每增加一张表就相当于增加了一次嵌套的循环,数量级增长会非常快,严重影响查询的效率。

#其次,`对 WHERE 条件创建索引`,因为 WHERE 才是对数据条件的过滤。如果在数据量非常大的情况下,没有 WHERE 条件过滤是非常可怕的。

#最后,`对用于连接的字段创建索引`,并且该字段在多张表中的`类型必须一致`。比如 course_id 在 student_info 表和 course 表中都为 int(11) 类型,而不能一个为 int 另一个为 varchar 类型。


SELECT s.course_id, NAME, s.student_id, c.course_name
FROM student_info s JOIN course c
ON s.course_id = c.course_id
WHERE NAME = '462eed7ac6e791292a79'; #0.001s

DROP INDEX idx_name ON student_info;


SELECT s.course_id, NAME, s.student_id, c.course_name
FROM student_info s JOIN course c
ON s.course_id = c.course_id
WHERE NAME = '462eed7ac6e791292a79'; #0.227s


#⑦使用列的类型小的创建索引

#⑧使用字符串前缀创建索引

#⑨ 区分度高(散列性高)的列适合作为索引

#⑩ 使用最频繁的列放到联合索引的左侧
SELECT *
FROM student_info
WHERE student_id = 10013 AND course_id = 100;

#补充:在多个字段都要创建索引的情况下,联合索引优于单值索引

# 3. 哪些情况不适合创建索引
# ① 在where中使用不到的字段,不要设置索引

# ② 数据量小的表最好不要使用索引

# ③ 有大量重复数据的列上不要建立索引
#结论:当数据重复度大,比如`高于 10% `的时候,也不需要对这个字段使用索引。

#④ 避免对经常更新的表创建过多的索引

#⑤ 不建议用无序的值作为索引

# ⑥ 删除不再使用或者很少使用的索引

# ⑦ 不要定义冗余或重复的索引

7.2哪些情况适合创建索引

1. 字段的数值有唯一性的限制

2.频繁作为 WHERE 查询条件的字段

3.经常 GROUP BY 和 ORDER BY 的列

4.UPDATE、DELETE 的 WHERE 条件列

5.DISTINCT 字段需要创建索引

6.多表 JOIN 连接操作时,创建索引注意事项

连接表的数量尽量不要超过 3 张、 对 WHERE 条件创建索引 、 对用于连接的字段创建索引,并且该字段在多张表中的 类型必须一致

7.使用列的类型小的创建索引

8.使用字符串前缀创建索引

公式:

1
count(distinct left(列名, 索引长度))/count(*)

一般长度为 20 的索引能区分90%的问题

9.区分度高(散列性高)的列适合作为索引

eg:id适合,gender不适合

10.使用最频繁的列放到联合索引的左侧

11.在多个字段都要创建索引的情况下,联合索引优于单值索引

因为查单值得时候可以用联合索引

补充:限制索引的数目(一般6个)

7.3哪些情况不适合创建索

① 在where中使用不到的字段,不要设置索引

② 数据量小的表最好不要使用索引

③ 有大量重复数据的列上不要建立索引

#结论:当数据重复度大,比如高于 10% 的时候,也不需要对这个字段使用索引。

④ 避免对经常更新的表创建过多的索引

⑤ 不建议用无序的值作为索引

⑥ 删除不再使用或者很少使用的索引

⑦ 不要定义冗余或重复的索引