目录
MySQL索引及执行计划
什么是索引?
1)索引就好比一本书的目录,它能让你更快的找到自己想要的内容。
2)让获取的数据更有目的性,从而提高数据库检索数据的性能。
给指定字段创建索引,索引会将该字段中所有数据进行排序
索引不是越多越好
创建索引,会占用磁盘空间
索引的排序方式
1)BTREE:B+树索引
2)HASH:HASH索引
3)FULLTEXT:全文索引
4)RTREE:R树索引
BTtree
三路Btree
- 根节点
- 枝节点
- 叶子节点
B+Tree
1)在叶子节点添加了相邻节点的指针
2)优化了范围查询,提升了范围查询的执行效率
选择5.7的mysql里用的就是B+Tree但是显示的是BTREE这个只是统称。
B*Tree
还真是概念类
索引管理
索引分类
-
主键索引(聚簇索引)
特性:唯一且非空
- 联合索引
-
唯一键索引
特性:唯一 可以为空
- 前缀索引
- 联合索引
-
普通索引
特性:可以不唯一,可以为空
- 前缀索引
- 联合索引
索引的增删查
表数据准备
# 建库
create database zls;
# 建表
create table student(
id int,
name varchar(10),
age tinyint,
gender enum('m','f'),
phone char(11)
);
# 传送数据
insert into student values
(1,'zls',18,'m',11111111111),
(2,'a',12,'f',11111131111),
(3,'b',13,'f',11241131111),
(4,'a',14,'m',11121131111);
root@localhost [zls] >select * from student;
+----+------+------+--------+-------------+
| id | name | age | gender | phone |
+----+------+------+--------+-------------+
| 1 | zls | 18 | m | 11111111111 |
| 2 | a | 12 | f | 11111131111 |
| 3 | b | 13 | f | 11241131111 |
| 4 | a | 14 | m | 11121131111 |
+----+------+------+--------+-------------+
主键索引primary
## 增
root@localhost [zls] >alter table student add primary key(id);
## 删
root@localhost [zls] >alter table student drop primary key;
# 索引类型的字段:key:(PRI:主键,UNI:唯一键,MUL:普通键)
## 查
root@localhost [zls] >desc student;
+--------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(10) | YES | | NULL | |
| age | tinyint(4) | YES | | NULL | |
| gender | enum('m','f') | YES | | NULL | |
| phone | char(11) | YES | | NULL | |
+--------+---------------+------+-----+---------+-------+
2.#-----
root@localhost [zls] >show index from student;
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| student | 0 | PRIMARY | 1 | id | A | 4 | NULL | NULL | | BTREE | | |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3.#-----
root@localhost [zls] >show index from student\G
*************************** 1. row ***************************
Table: student // 索引所属的表名
Non_unique: 0 // 指示索引是否允许重复值。值为0表示唯一索引,值为1表示非唯一索引。
Key_name: PRIMARY // 显示索引的名称。
Seq_in_index: 1 // 显示列在联合索引中的位置。对于单列索引,序列号始终为1。
Column_name: id // 显示索引所涵盖的列名。
Collation: A // 指定索引使用的排序规则。
Cardinality: 4 // 表示索引中不重复的值的估计数量。
Sub_part: NULL // 如果索引是部分索引,则显示部分索引定义的长度。
Packed: NULL // 用于存储索引值的压缩类型。
Null: // 指示列是否允许为空值(YES表示允许,空白表示不允许)。
Index_type: BTREE // 指示索引的类型,如BTREE、HASH等。
Comment: // 可选的注释信息。
Index_comment: // 索引的注释信息。
4.#-----
root@localhost [zls] >show create table student;
student | CREATE TABLE `student` (
`id` int(11) NOT NULL,
`name` varchar(10) DEFAULT NULL,
`age` tinyint(4) DEFAULT NULL,
`gender` enum('m','f') DEFAULT NULL,
`phone` char(11) DEFAULT NULL,
PRIMARY KEY (`id`), // 主键
UNIQUE KEY `uni_phone` (`phone`), // 唯一键
KEY `name` (`name`) // 普通键
) ENGINE=InnoDB DEFAULT CHARSET=utf8
唯一键索引unique
## 增
# 统计,统计去重
root@localhost [zls] >select count(name) from student;
+-------------+
| count(name) |
+-------------+
| 4 |
+-------------+
root@localhost [zls] >select count(distinct(name)) from student;
+-----------------------+
| count(distinct(name)) |
+-----------------------+
| 3 |
+-----------------------+
root@localhost [zls] >select count(age) from student;
+------------+
| count(age) |
+------------+
| 4 |
+------------+
root@localhost [zls] >select count(distinct(age)) from student;
+----------------------+
| count(distinct(age)) |
+----------------------+
| 4 |
+----------------------+
### 要创建唯一键的时候去重前后的数值要一样,
## 1.不给索引起名
root@localhost [zls] >alter table student add unique key(age);
## 2.给索引起名
root@localhost [zls] >alter table student add unique key uni_phone(phone);
## 删
root@localhost [zls] >alter table student drop index age;
root@localhost [zls] >alter table student drop key uni_phone;
普通索引
## 创建
# 表内有重复的也可以创建,这样的索引。慢
# 1.不起名,以字段名,命名
root@localhost [zls] >alter table student add index(name);
# 2.起名
root@localhost [zls] >alter table student add key idx_name(name);
## 删除
root@localhost [zls] >alter table student drop index idx_name;
root@localhost [zls] >alter table student drop key name;
前缀索引
什么是前缀索引?
创建索引时,按照指定数值对列进行排序
为什么使用前缀索引?
1)给大列创建索引时,可以减少排序时间,提升创建索引速度
2)insert,update,delete插入数据时,提升写入速度
3)提升查询速率
## 唯一键前缀索引创建
root@localhost [zls] >alter table student add unique key uni_phone(phone(7));
## 普通索引创建
root@localhost [zls] >alter table student add key idx_name(name(2));
联合索引
## 主键联合索引
root@localhost [zls] >alter table student add primary key(id,name);
## 唯一键联合索引创建
root@localhost [zls] >alter table student add unique key uni_all(gender,age,phone);
## 普通索引创建联合索引
root@localhost [zls] >alter table student add index idx_all(gender,age,phone);
## 删除
root@localhost [zls] >alter table student drop index idx_all;
root@localhost [zls] >alter table student drop key idx_all;
## 查询规则
alter table student add index idx_all(a,b,c,d);
where a.女生 and b.身高 and c.体重 and d.身材好
index(a,b,c)
特点:前缀生效特性
a,ab,ac,abc,abcd 可以走索引或部分走索引
b bc bcd cd c d ba ... 不走索引
网站访问速度慢,如何排查,如何解决?
- 网络问题
- 设备配置
- 代码bug
- 应用(nginx、lb、proxy)
- 数据库慢查询
使用explain分析SQL语句
慢查询,开启慢查询日志,记录执行速度慢的SQL语句
找出执行慢的SQL语句后,使用explain进行分析
# 在查询语句前面加上explain
root@localhost [zls] >explain select * from student;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
| 1 | SIMPLE | student | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | NULL |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
root@localhost [zls] >explain select * from student\G
*************************** 1. row ***************************
id: 1 // 表示当前行的标识符。在单个查询中,如果有多个表被连接,每个表都会有一个唯一的标识符。
select_type: SIMPLE // 表示查询的类型。常见的类型包括SIMPLE、PRIMARY、SUBQUERY等。
table: student // 表示查询涉及的表名。
partitions: NULL // 表示查询涉及的分区信息。
type: ALL // 表示访问表的方式或连接类型。常见的类型包括ALL、index、range、ref等。较好的连接类型通常是使用索引(index)或范围查找(range)。
possible_keys: NULL // 表示可能用于此查询的索引列表。
key: NULL // 表示实际使用的索引。如果为NULL,则表示没有使用索引。
key_len: NULL // 表示使用的索引的长度。较小的长度通常是更好的。
ref: NULL // 表示与索引匹配的列或常数。
rows: 4 // 表示根据表统计信息估计出的查询返回的行数。
filtered: 100.00 // 表示在表中过滤记录所占的百分比。
Extra: NULL // 表示关于查询执行的附加信息,例如使用了临时表(Temporary Table)、文件排序(Filesort)等。
Type:全量扫描
练习用表结构
root@localhost [world] >desc city;
+-------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| Name | char(35) | NO | | | |
| CountryCode | char(3) | NO | MUL | | |
| District | char(20) | NO | | | |
| Population | int(11) | NO | MUL | 0 | |
+-------------+----------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
全表扫描
- ALL
root@localhost [world] >explain select * from city where district='shanghai'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4188
filtered: 10.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)
index:全索引扫描
索引扫描
root@localhost [world] >explain select countrycode from city\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
partitions: NULL
type: index
possible_keys: NULL
key: CountryCode
key_len: 3
ref: NULL
rows: 4188
filtered: 100.00
Extra: Using index
1 row in set, 1 warning (0.00 sec)
range:范围扫描
一般来说一条sql语句能达到range级别就ok了
root@localhost [world] >explain select * from city where population < 100\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
partitions: NULL
type: range
possible_keys: Population
key: Population
key_len: 4
ref: NULL
rows: 1
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
ref:非唯一索引
root@localhost [world] >explain select * from city where countrycode='CHN' union all select * from city where countrycode='USA'\G
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: city
partitions: NULL
type: ref
possible_keys: CountryCode
key: CountryCode
key_len: 3
ref: const
rows: 363
filtered: 100.00
Extra: NULL
*************************** 2. row ***************************
id: 2
select_type: UNION
table: city
partitions: NULL
type: ref
possible_keys: CountryCode
key: CountryCode
key_len: 3
ref: const
rows: 274
filtered: 100.00
Extra: NULL
2 rows in set, 1 warning (0.00 sec)
eq_ref:只有在连表查询时,使用join on 才能出现
并且在连接条件中使用了唯一索引或主键列时,优化器可以通过索引快速定位到满足条件的行,从而提供更高效的查询性能。
root@localhost [linux50] >select * from score;
+-----+-----+------+
| sno | cno | mark |
+-----+-----+------+
| 1 | 2 | 30.0 |
+-----+-----+------+
1 row in set (0.00 sec)
root@localhost [linux50] >select * from student;
+-----+-------+------+------+---------------------+-------+
| sno | sname | sage | ssex | sbirthday | class |
+-----+-------+------+------+---------------------+-------+
| 1 | 旭 | 20 | 1 | 2023-07-26 17:33:14 | 5 |
| 2 | 东 | 21 | 1 | 2023-07-26 17:33:27 | 5 |
| 3 | 徐 | 22 | 1 | 2023-07-26 17:33:39 | 5 |
+-----+-------+------+------+---------------------+-------+
3 rows in set (0.00 sec)
root@localhost [linux50] >explain select score.mark from student join score on student.sno=score.sno where student.sname='旭'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: score
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
filtered: 100.00
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: student
partitions: NULL
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: linux50.score.sno
rows: 1
filtered: 50.00
Extra: Using where
2 rows in set, 1 warning (0.00 sec)
const、system 主键精准查询时
root@localhost [world] >explain select * from city where id=10\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
partitions: NULL
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
null
root@localhost [world] >explain select * from city where population>1000000000000000000000000000000000000000000000000000\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: NULL
partitions: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
filtered: NULL
Extra: no matching row in const table
1 row in set, 1 warning (0.00 sec)
没有走索引原因?
该字段没创建索引
创建索引了,但是没走
不使用where条件
# 1.使用select * 查询数据不接where条件(杀个程序员祭天)
root@localhost [world] >explain select * from city;
查询结果集大于25%
root@localhost [world] >explain select * from city where population > 1000\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
partitions: NULL
type: ALL
possible_keys: Population
key: NULL
key_len: NULL
ref: NULL
rows: 4188
filtered: 97.13 // 表中占比97.13
Extra: Using where
1 row in set, 1 warning (0.00 sec)
使用limit分页查询方式优化结果集
root@localhost [world] >explain select * from city where population > 1000 limit 60\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
partitions: NULL
type: range
possible_keys: Population
key: Population
key_len: 4
ref: NULL
rows: 4068
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
使用字段列做计算
同不加where条件的一起。
root@localhost [world] >explain select * from city where id-1=10\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4188
filtered: 100.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)
## 可行的计算方法
root@localhost [world] >explain select * from city where id=10-1\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
partitions: NULL
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
隐式转换导致索引失效
## 创建表时,数据类型和查询时不一致导致,不走索引
字符串类型:加引号
root@localhost [world] >explain select * from user where phone='21111111111';
数字类型:不加引号
root@localhost [world] >explain select * from user where phone=21111111111;
使用like模糊查询时,%在前面的
如果需求是必须百分号在前面,不要使用MySQL
请使用elastsearch
root@localhost [world] >explain select * from city where countrycode like '%h'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4188
filtered: 11.11
Extra: Using where
1 row in set, 1 warning (0.00 sec)
root@localhost [world] >explain select * from city where countrycode like 'h%'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
partitions: NULL
type: range
possible_keys: CountryCode
key: CountryCode
key_len: 3
ref: NULL
rows: 22
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
使用 <> 、 not in查询数据
root@localhost [world] >explain select * from city where countrycode not in ('CHN','USA');
root@localhost [world] >explain select * from city where countrycode <> 'CHN' and countrycode <> 'USA';
root@localhost [world] >explain select * from city where countrycode <> 'CHN' and countrycode <> 'USA'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
partitions: NULL
type: ALL
possible_keys: CountryCode
key: NULL
key_len: NULL
ref: NULL
rows: 4188
filtered: 82.19
Extra: Using where
1 row in set, 1 warning (0.00 sec)
root@localhost [world] >explain select * from city where countrycode <> 'CHN' and countrycode <> 'USA' limit 10\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
partitions: NULL
type: range
possible_keys: CountryCode
key: CountryCode
key_len: 3
ref: NULL
rows: 3442
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
联合索引,where条件后面没有按照创建索引的顺序查询
1)按顺序查
解决:2)用户行为分析(数据分析)
索引损坏,失效
删了索引
重建,使用前缀索引
索引创建原则
1)索引不是越多越好
索引的数目不是越多越好。每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。 修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新表变得很浪费时间。
2)有必要添加索引的列,如何选择索引?
删除不再使用或者很少使用的索引
表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理 员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。
# 1.优先选择,唯一键索引
# 2.给经常要排序、分组这种查询的列,创建联合索引
# 3.普通索引尽量使用前缀索引
标签:索引,select,key,SQL,NULL,root,localhost
From: https://www.cnblogs.com/xiutai/p/17749302.html