Mysql的索引执行计划

索引的介绍
1)索引就好比一本书的目录,它能让你更快的找到自己想要的内容。
2)让获取的数据更有目的性,从而提高数据库检索数据的性能。

索引算法类型

1、Btree算法:B树算法 (当前mysql默认的算法)>
2、HASH:哈希算法
3、Fulltext:全文算法
4、Rtree:R数算法
使用什么算法的索引,根mysql的存储引擎有关(innodb)

1
2
root@localhost:(none) > show engines;
哈希算法只能用在MEMORY

Btree算法

image-20240815090340158

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#规律: 三路Btree
1、每一个数据页上面都有3个数据
2、P1 P2 P3叫数据页
3、每一页上的值,都是下一路数据上的最小值

Btree算法是创建索引之后的排序规则
根分支:(根节点)
中间部分:枝节点
最顶上:叶子节点

#精确查询
select * from tb1 where id=32; 这条语句经过3次IO
如果没有索引,一直扫描到100,然后再把32取出来

#范围查询
select * from tb1 where id>25 and id<36; 9次IO
范围越大,IO次数越多

B+tree 索引 (mysql默认的算法)

image-20240815084835397

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#规律: 三路Btree
1、每一个数据页上面都有3个数据
2、P1 P2 P3叫数据页
3、每一页上的值,都是下一路数据上的最小值

Btree算法是创建索引之后的排序规则
根分支:(根节点)
中间部分:枝节点
最顶上:叶子节点

#精确查询
select * from tb1 where id=32; 3次IO
如果没有索引,一直扫描到100,然后再把32取出来

#范围查询
select * from tb1 where id>25 and id<36; 5次IO,因为他不回到根节点
IO发生的次数越少,效率越快

#Btree算法和B+tree的区别
1、B+tree算法优化了范围查询
2、在相邻的叶子节点上添加了指针(Q就是指针)

B*tree 基本上不怎么用

image-20240815132635119

索引的分类

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
1、#主键索引(聚簇索引):index
- 可以创建联合索引


2、#唯一键索引:unique key
- 可以创建联合索引
- 可以创建前缀索引

3、#普通索引:primary key
- 可以创建联合索引
- 可以创建前缀索引

#查看一张表的索引方法:
查看表结构的方法:
root@localhost:(none) > desc mysql.user;
----
Key #key列的就是索引
----
PRI
PRI

建表语句的方法查看:
root@localhost:(none) > show create table mysql.user;
PRIMARY KEY (`Host`,`User`)

查看一张表里面都有哪些索引
show index from 表名;
root@localhost:(none) > show index from mysql.user;

Key_name #索引名字
PRIMARY
PRIMARY

Index_type #索引类型 B树算法的统称都叫Btree
BTREE
BTREE

注意:索引不是越多越好,避免给大列创建索引>
1.索引会进行排序,大列创建索引速度慢
2.索引越多占用磁盘空间越大

1、首先你给一个字段添加索引,mysql的底层会进行Btree算法进行排序,在排序的时候就要花时间,
2、索引越多占用磁盘空间,
3、虽然查询速度快,insert、update、delete处理数据的时候会耗时,他会重新排序

索引的操作

1、普通索引 index

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
#在企业中,不确定表里面有多少数据,敢不敢用select *?
#先统计一下行数
root@localhost:student > select count(*) from world.city;
+----------+
| count(*) |
+----------+
| 4079 |
+----------+


root@localhost:student > desc stu5;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | | 0 | |
| name | varchar(10) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
1、添加普通索引
#给name字段添加普通索引(里面的值可以为空,也可以重复,就是为了查询的速度快)
alter table 表名 add index 索引名(字段);

root@localhost:student > alter table stu5 add index idx_name(name);
root@localhost:student > desc stu5;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | | 0 | |
| name | varchar(10) | YES | MUL | NULL | |
+-------+-------------+------+-----+---------+-------+
root@localhost:student > show index from stu5;

2、删除普通索引
root@localhost:student > alter table stu5 drop index idx_name;

root@localhost:student > show index from stu5; #查看表里面有哪些索引,发现是空的,删除成功
Empty set (0.00 sec)

#索引没有改 只能增删查
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
有索引和无索引的区别

#查看表里面的全部索引
show index from world.city;

#表里面4079,读的时候读了4188行
root@localhost:student > select * from world.city;
4079 rows in set (0.01 sec)
分析sql语句
root@localhost:student > explain select * from world.city;
rows #行数
----
4188
精确查询一个城市,还是4188行
root@localhost:student > explain select * from world.city where name='Odessa';
rows
----
4188
原因:在没有索引的情况下,进行全表扫描了

#查看有索引的字段名,并进行分析
root@localhost:student > select * from world.city where population=92020;
root@localhost:student > explain select * from world.city where population=92020;
rows #行数只要1行
----
1
在有索引的情况下,只查出了1行,因为添加索引之后,已经排好序了

2、唯一键索引 unique key

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
主键索引的速度一定是最快的,但是一张表里面只有一个主键,优先考虑唯一键索引,他的速度仅次于主键索引
创建唯一键索引的前提不能有重复的值

#判断一个列能不能创建唯一键索引的方法:
1、先统计一下有多少行
root@localhost:student > select count(population) from world.city;
+-------------------+
| count(population) |
+-------------------+
| 4079 |
+-------------------+
2、再去统计一下去重后的行数
root@localhost:student > select count(distinct(population)) from world.city;
+-----------------------------+
| count(distinct(population)) |
+-----------------------------+
| 3897 |
+-----------------------------+
3、对比数据,发现数据变少了,说明有重复的值,不能使用唯一键索引,只能创建普通索引
4、创建普通索引
root@localhost:student > alter table world.city add index idx_population(population);

#创建唯一键索引
root@localhost:student > alter table stu3 add unique key uni_phone(phone);
查看
root@localhost:student > show index from stu3;

#删除唯一键索引
root@localhost:student > alter table stu3 drop index uni_phone;

3、主键索引(聚簇索引):primary key

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
#建表时创建主键索引
root@localhost:student > create table stu4(id int primary key auto_increment,name varchar(10));
root@localhost:student > create table stu4(id int auto_increment,name varchar(10),primary key(id));

#添加主键索引
root@localhost:student > create table stu5(id int,name varchar(10));
root@localhost:student > desc stu5;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(10) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
这个表创建的时候没有加主键,需要添加主键

root@localhost:student > alter table stu5 add primary key(id);

root@localhost:student > desc stu5; #查看到主键索引已添加
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | 0 | |
| name | varchar(10) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+

#删除主键索引
root@localhost:student > alter table stu5 drop primary key;
如果索引里面有数据 是删不掉的


#索引有专门的添加方式,不能用改字段的方式去修改
  • 前缀索引
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
为什么有前缀索引:解决给大列创建的索引排序时,解决排序速度慢的问题

1、#普通索引创建一个前缀索引
root@localhost:student > alter table stu3 add index idex_phone(phone(3));
指定这个字段排序时,优先按前3个字符排序,就不是按完整字符排序了

#查看建表语句: 可以看到他是前缀索引,按3个字符排序
root@localhost:student > show create table stu3;
KEY `idex_phone` (`phone`(3))
root@localhost:student > show index from stu3;
Sub_part
---------
3


2、#唯一索引创建前缀索引 前提条件,指定的前几个字符不能重复
先把上次创建的前缀索引删除
root@localhost:student > alter table stu3 drop index idex_phone;
root@localhost:student > alter table stu3 add unique key uni_phone(phone(3)); #会报错
ERROR 1062 (23000): Duplicate entry '123' for key 'uni_phone'
唯一索引前缀:按前3个字符排序,但是前3个字符不能一样

按最后一个字符排序
root@localhost:student > alter table stu3 add unique key uni_phone(phone(11));
root@localhost:student > show index from stu3;
Sub_part
----------
NULL #手机号的总长度就是11,相当于没写这个前缀,除非前缀不一样,不重复
# 一般手机号的列,很少创建唯一索引


3、#主键索引创建前缀索引 #无法创建,主键索引不支持前缀
alter table stu2 add primary key(id(3));
  • 联合索引
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
一张表里面哪些字段需要创建索引,取决于:用户需求
一个数据,用户经常查,一定是对这个字段需求量比较大,就要提高这个字段查询的效率

当一张表中,需要创建索引的字段比较多的时候,就可以用联合索引

1、#创建普通索引的联合索引
多个字段建立一个索引
#原则:把最常用来做为条件查询的列放在最前面

#创建相亲表
create table xiangqin(id int comment '序号',
name varchar(10) comment '姓名',
gender enum('0','1') comment '性别',
high int comment '身高',
weight int comment '体重',
body varchar(10) comment '身材',
salary int) comment '收入';

1)、#假设用户最关注的是:
性别:gender
收入:salary
身材:body

2)、#根据用户喜好创建联合索引创建联合索引
root@localhost:student > alter table xiangqin add index idx_all(gender,salary,body);
如果创建的时候,把body放第一个,用户查询的时候就不走索引,这个索引等于没建
查看:
root@localhost:student > show index from xiangqin;

创建联合索引+前缀索引
root@localhost:student > alter table xiangqin add index idex_all(gender,salary(4),body);

root@localhost:student > desc xiangqin;
| gender | enum('0','1') | YES | MUL | NULL | #只看到排序的第一个有索引
root@localhost:student > show index from xiangqin; #可以看全

例:
当:a.女生 and b.身高 and c.体重 and d.身材好
index(a,b,c)
特点:前缀生效特性
a,ab,ac,abc,abcd 可以走索引或部分走索引
b bc bcd cd c d ba ... 不走索引 只要a不在前面,就不走索引


2、#唯一索引创建联合索引
先删除上次创建的索引
root@localhost:student > alter table xiangqin drop index idx_all;
字段的数据不能重复

root@localhost:student > alter table xiangqin add unique key uni_all(gender,salary,body);

3、#主键索引创建联合索引
先删除上次创建的索引
root@localhost:student > alter table xiangqin drop index uni_all;

创建主键索引
root@localhost:student > alter table xiangqin add primary key(gender,salary,body);

root@localhost:student > desc xiangqing #3个都显示
1
2
3
分析慢查询语句,需要开启慢查询日志,他会把慢的sql语句记录进去

mysql执行慢,可能和扫描有关

Mysql数据扫描

1、全表扫描

1
2
3
4
5
6
7
8
9
10
11
#什么情况下出现全表扫描
情况1、select * from tb1;
情况2、select 查询数据时,where条件接的字段,没有创建索引 (不走索引,就是全表扫描)

root@localhost:student > explain select * from world.city;
+----+-------------+-------+------+---------------+------+---------+------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+------+---------------+------+---------+------+------+
| 1 | SIMPLE | city | ALL | NULL | NULL | NULL | NULL | 4188 |
+----+-------------+-------+------+---------------+------+---------+------+------+
#可以看到type类型是ALL 扫描的行数是4188行

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
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
#索引扫描就是走索引查询(走索引,也有快慢之分,不是走索引了就一定快)

常见的走索引扫描类型:
1)index
2)range
3)ref
4)eq_ref
5)const、system
6)null


1、# index:全索引扫描(最慢,和全表扫描没什么区别)
root@localhost:student > show index from world.city;
它做了普通索引的,只查countrycode这一列

root@localhost:student > select countrycode from world.city;
#explain就是分析sql语句
root@localhost:student > explain select countrycode from world.city;
+----+-------------+-------+-------+---------------+-------------+---------+------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+
| 1 | SIMPLE | city | index | NULL | CountryCode | 3 | NULL | 4188 |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+
#可以看到type类型是index 扫描的行数是4188行

2、# range:范围查询并创建了索引 只要能达到rang级别,就是OK的 如果想把range优化到system的级别,是不能实现的,system级别只能主键索引能到底
root@localhost:student > select * from world.city where population<1000;
root@localhost:student > explain select * from world.city where population<1000;
+----+-------------+-------+-------+----------------+----------------+---------+------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+-------+----------------+----------------+---------+------+------+
| 1 | SIMPLE | city | range | idx_population | idx_population | 4 | NULL | 11 |
+----+-------------+-------+-------+----------------+----------------+---------+------+------+
#可以看到type类型是range 扫描的行数是11行


#这两个效率一样
root@localhost:student > explain select * from world.city where countrycode='CHN' or countrycode='USA';
root@localhost:student > explain select * from world.city where countrycode in ('CHN','USA');
+----+-------------+-------+-------+---------------+-------------+---------+------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+
| 1 | SIMPLE | city | range | CountryCode | CountryCode | 3 | NULL | 637 |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+
#可以看到type类型是range 扫描的行数是637行

#优化到ref级别
root@localhost:student > explain select * from world.city where countrycode='CHN' union all select * from world.city where countrycode='USA';
+----+--------------+------------+------+---------------+-------------+---------+-------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+--------------+------------+------+---------------+-------------+---------+-------+------+
| 1 | PRIMARY | city | ref | CountryCode | CountryCode | 3 | const | 363 |
| 2 | UNION | city | ref | CountryCode | CountryCode | 3 | const | 274 |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL
+----+--------------+------------+------+---------------+-------------+---------+-------+------+
#可以看到type类型是ref 扫描的行数是分开的

3、# ref:联合查询、普通索引的精确查询
联合查询
root@localhost:student > explain select * from world.city where countrycode='CHN' union all select * from world.city where countrycode='USA';

普通索引的精确查询才能到底ref级别
root@localhost:student > explain select * from world.city where countrycode='CHN';
+----+-------------+-------+------+---------------+-------------+---------+-------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+
| 1 | SIMPLE | city | ref | CountryCode | CountryCode | 3 | const | 363 |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+
#可以看到type类型是ref 扫描的行数是363行


4、# eq_ref:只有在连表查询使用 join on,且小表在前,大表在后
join B
on A.sid=B.sid


5、# const、system:主键查询的精确查询
root@localhost:student > explain select * from world.city where id=10;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+
| 1 | SIMPLE | city | const | PRIMARY | PRIMARY | 4 | const | 1 |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+
#可以看到type类型是const 扫描的行数是1行


6、# null:让mysql啥也不干 性能才是最高的,这个基本上不会出现的
root@localhost:student > explain select * from world.city where population>10000000000; #按Btree算法来看,已经不在排序范围了,已经超过记录了
+----+-------------+-------+------+---------------+------+---------+------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+------+---------------+------+---------+------+------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
+----+-------------+-------+------+---------------+------+---------+------+------+
#可以看到type类型是NULL 扫描的行数是NULL行

非要优化到system级别的 只能创建主键索引,但是主键索引只能有一个 所以不能优化
不是创建了索引,就走索引扫描


key_len的列: 越小越好,可以拿前缀索引去控制
rows的列: 越小越好

索引的创建规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#这个可能用不到,因为一般企业里面的表早就建好了
为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索引和创建什么类型的索引。
1、每张表必须有一个主键索引

2、主键索引只能创建一个,但要对某个字段创建索引,优先考虑能创建唯一索引就创建唯一索引
#需要先判断是否能创建唯一索引
root@localhost:zls 10:12:29> select count(population) from world.city;
root@localhost:zls 10:12:43> select count(distinct(population)) from world.city;

3、如果重复值比较多的情况下,联合索是优先的,可以用普通索引的联合索引


4、为经常需要排序、分组和联合操作的字段建立索引
例如:
经常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段,排序操作会浪费很多时间。
如果为其建立索引,可以有效地避免排序操作

5、为常作为查询条件的字段建立索引
如果某个字段经常用来做查询条件,那么该字段的查询速度会影响整个表的查询速度。
因此,为这样的字段建立索引,可以提高整个表的查询速度。

注:如果经常作为条件的列,重复值特别多,可以建立联合索引

6、尽量使用前缀来索引,创建的索引能加前缀的加前缀,唯一索引也可以加
  • 限制索引的数目
    索引的数目不是越多越好。每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。
    修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新表变得很浪费时间。
  • 删除不再使用或者很少使用的索引
    用户的喜好会发生变化的,要经常调用哪些字段用户查询减少,把表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。

怎么判断不走索引

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
#不是创建了索引,就一定走索引
使用explain判断是否走索引

1、#没创建索引


2、#当你查的数据的结果集超过总数据25% 你的数据有100条,查询出来的时候有125条
示例
假设一个数据库表students,包含100条记录。执行了一个查询来查找年龄大于18岁的学生,并得到了30条记录作为结果集。
总数据量:100条记录
结果集大小:30条记录
比例计算:(30 / 100) * 100% = 30%
结论:结果集超过了总数据的25%(因为30% > 25%)

root@localhost:student > explain select * from world.city where Population>1000;
4068 rows in set (0.01 sec) #得到的结果集4068
root@localhost:student > explain select * from world.city where Population>1000;
+----+-------------+-------+------+----------------+------+---------+------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+------+----------------+------+---------+------+------+
| 1 | SIMPLE | city | ALL | idx_population | NULL | NULL | NULL | 4188 |
+----+-------------+-------+------+----------------+------+---------+------+------+

#优化方案: 使用limit,分页查询
root@localhost:student > select * from world.city where population>1000 limit 10;
root@localhost:student > explain select * from world.city where population>1000 limit 10;
+----+-------------+-------+-------+----------------+----------------+---------+------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+-------+----------------+----------------+---------+------+------+
| 1 | SIMPLE | city | range | idx_population | idx_population | 4 | NULL | 4067 |
+----+-------------+-------+-------+----------------+----------------+---------+------+------+

3、#使用字段做计算 id+1=10这样使用字段做计算,不走索引 id=10-1 会走索引
#id=10-1 会走索引
root@localhost:student > select * from world.city where id=10-1;
root@localhost:student > explain select * from world.city where id=10-1;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+
| 1 | SIMPLE | city | const | PRIMARY | PRIMARY | 4 | const | 1 |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+

#id+1=10 不走索引
root@localhost:student > select * from world.city where id+1=10;
+----+-----------+-------------+---------------+------------+
| ID | Name | CountryCode | District | Population |
+----+-----------+-------------+---------------+------------+
| 9 | Eindhoven | NLD | Noord-Brabant | 201843 |
+----+-----------+-------------+---------------+------------+

root@localhost:student > explain select * from world.city where id+1=10;
+----+-------------+-------+------+---------------+------+---------+------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+------+---------------+------+---------+------+------+
| 1 | SIMPLE | city | ALL | NULL | NULL | NULL | NULL | 4188 |
+----+-------------+-------+------+---------------+------+---------+------+------+

4、#隐式转换导致不走索引
phone字段是char类型的 插入的时候没有加引号
1)、先查看这个表,phone有索引,数据类型是char(11)
root@localhost:student > desc stu3;
+-----------+---------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
| age | tinyint(4) unsigned | NO | | NULL | |
| gender | enum('m','f') | NO | | m | |
| phone | char(11) | NO | PRI | NULL | |
| come_time | datetime | NO | | CURRENT_TIMESTAMP | |
| status | enum('0','1') | NO | | 0 | |
+-----------+---------------------+------+-----+-------------------+----------------+
2)、插入一条数据
root@localhost:student > insert into stu3 values(8,'wang6u',22,'m',12121212127,now(),'0'); #phone插入的时候没有加引号
3)、查询的时候也是没有加引号,没有走索引
root@localhost:student > explain select * from stu3 where phone=12121212127;
+----+-------------+-------+------+---------------+------+---------+------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+------+---------------+------+---------+------+------+
| 1 | SIMPLE | stu3 | ALL | uni_phone | NULL | NULL | NULL | 7 |
+----+-------------+-------+------+---------------+------+---------+------+------+
4)查询的时候加引号,走索引
root@localhost:student > explain select * from stu3 where phone='12121212127';
+----+-------------+-------+-------+---------------+-----------+---------+-------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+-------+---------------+-----------+---------+-------+------+
| 1 | SIMPLE | stu3 | const | uni_phone | uni_phone | 33 | const | 1 |
+----+-------------+-------+-------+---------------+-----------+---------+-------+------+

#优化:查询字段的数据类型按照指定的数据类型进行查询


5、#模糊查询 %不能放前面,因为%不固定,全表都要扫描,范围大
%放前面,不走索引
root@localhost:student > explain select * from world.city where countrycode like '%H';
+----+-------------+-------+------+---------------+------+---------+------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+------+---------------+------+---------+------+------+
| 1 | SIMPLE | city | ALL | NULL | NULL | NULL | NULL | 4188 |
+----+-------------+-------+------+---------------+------+---------+------+------+

%没放前面,走索引
root@localhost:student > root@localhost:student > explain select * from world.city where countrycode like 'H%';
+----+-------------+-------+-------+---------------+-------------+---------+------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+
| 1 | SIMPLE | city | range | CountryCode | CountryCode | 3 | NULL | 22 |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+

#优化:如果生产中有大量的这种%放前面才能查询的需求,那就不使用mysql,
#可以用elasticsearch,他是专门做搜索引擎的数据库

6、#范围查询时,使用<>、 not in 、!=
使用这种方法必然会不走索引,因为不等于1个值,其它的都出来了,结果集必定>25%
root@localhost:student > explain select * from world.city where countrycode != 'CHN';
+----+-------------+-------+------+---------------+------+---------+------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+------+---------------+------+---------+------+------+
| 1 | SIMPLE | city | ALL | CountryCode | NULL | NULL | NULL | 4188 |
+----+-------------+-------+------+---------------+------+---------+------+------+
归根结底还是结果集导致不走索引

#优化:使用limit
root@localhost:student > explain select * from world.city where countrycode != 'CHN' limit 10;
+----+-------------+-------+-------+---------------+-------------+---------+------+------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+
| 1 | SIMPLE | city | range | CountryCode | CountryCode | 3 | NULL | 3715 |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+

7、#联合索引:当没有按照索引创建顺序查询,导致不走索引
#优化方案:做好调研,日志分析数据,按照用户需求,创建联合索引

8、索引本身失效
#优化方案:删除重建
判断索引是否失效,就是把上面的判断完了,都走索引了
1
2
3
4
5
6
7
网站访问慢,或者面试问
如果是物理机,就先排除硬件,或者网络,是不是网络延迟高,传输层,tcp,排查七层模型,最后到应用层,nginx的配置,是不是压力大抗不住
mysql是不是慢查询导致的速度慢,他会记录在日志里面,拿出来,加上explain 分析,
分析是全表扫描还是索引扫描,索引扫描了,是哪个级别,
如果是全表扫描,看看是不是没有创建索引,如果创建了索引,还是全表扫描,那原因是什么呢?

mysql的视图和触发器 是开发写的