MySQL索引相关知识整理学习
前言
一、MySQL索引
索引:用于快速查找数据。
索引是将数据的一些关键信息通过特定的数据结构存储到一片新的空间中,这样在文件查找的时候能快速找到。
MySQl主要有两种类型的索引:哈希索引、B+树索引
哈希索引
- 基于哈希表实现,取数据的哈希值,把这个哈希值来作为索引。
- 哈希索引可以以O(1)的时间复杂度进行查找,但是这样查找导致其失去了有序性,无法用于排序和分组、只支持精确查找,无法用于部分查找和范围查找。
B+树索引
- B+Tree:B+树,MySQL常用的一种索引类型,默认索引类型。
- 特点:因为不再需要进行全表扫描,只需要对树进行搜索即可,所以查找速度快很多。
因为 B+ Tree 的有序性,所以除了用于查找,还可以用于排序和分组。
可以指定多个列作为索引列,多个索引列共同组成键。
适用于全键值、键值范围和键前缀查找,其中键前缀查找只适用于最左前缀查找。如果不是按照索引列的顺序进行查找,则无法使用索引。
B+树的优点
B+树的磁盘IO更低;
B+树的查询也更加稳定(因为数据存储在叶子结点中,因此所有关键字的查询都必须是从根结点到叶子结点这样一条完整的路,所有的关键字查询的路径是相同的,因此每一个数据的查询效率都是一致的);
B+树的元素遍历效率更高,B+树只要遍历叶子结点就可以实现整棵树的遍历。
其中B+树索引可以分为聚簇索引和非聚簇索引
聚簇索引
- 主索引的叶子结点上保存着完整的数据记录。
非聚簇索引
- 索引的叶子结点上记录的是主键的值,在使用其进行查找的时候,需要先找到主键的值,然后再到主索引中进行查找,这个过程被称为回表。
聚簇索引和非聚簇索引的特点及区别:
聚簇索引有唯一性:因为其是把数据和索引结构放到一块的,因此一个表中只有一个聚簇索引
聚簇索引适合用在排序的场合,非聚簇索引不适合
取出一定范围的数据的时候,比较适合使用聚簇索引
可以把相关的数据保存到一起,在实现电子邮箱的时候,可以根据用户ID来聚集数据,这样只需要从磁>盘中读取少数的数据页就可以获取某个用户的全部邮件
innodb这个存储引擎就是聚集索引,因为索引和数据是放在一起的。
而myisam就是非聚集索引,索引和数据分开存放的。
聚簇索引的劣势:维护索引很昂贵,特别是插入新行或者主键被更新导致需要进行分页的时候
二、特殊类型的索引
1、覆盖索引
覆盖索引即从非主键索引中就能查到的记录,而不需要去查询主键索引中的记录,避免了回表的产生进而减少了树的搜索速度,可以显著提升性能。
2、联合索引
这个和覆盖索引很像,还是一个学生表为例,我们建立了name和age的联合索引,通过name可以直接查询到age,不需要回表操作。
思考:联合索引和覆盖索引的区别呢?
可以说覆盖索引是联合索引的最优解。
联合索引遵循最左侧匹配原则,比如(name,age),索引可以是name或者name和age的组合,看,后面这种情况就是覆盖索引,所以说,覆盖索引是联合索引的最优解。
3、最左前缀原则
在mysql建立联合索引的时候会遵循最左前缀匹配的原则,即最左侧的优先,在检索数据的时候从联合索引的最左边开始匹配,很多时候我们就可以根据最左前缀原则判断当前的查询能不能命中我们设定的索引。
4、索引下推
索引下推(index condition pushdown )简称ICP,在Mysql5.6的版本上推出,用于优化查询。
- 在不使用ICP的情况下,在使用非主键索引(又叫普通索引或者二级索引)进行查询时,存储引擎通过索引检索到数据,然后返回给MySQL服务器,服务器然后判断数据是否符合条件 。
- 在使用ICP的情况下,如果存在某些被索引的列的判断条件时,MySQL服务器将这一部分判断条件传递给存储引擎,然后由存储引擎通过判断索引是否符合MySQL服务器传递的条件,只有当索引符合条件时才会将数据检索出来返回给MySQL服务器 。
- 索引下推在非主键索引上的优化,可以有效的减少回表的次数,大大提升了查询的效率。
5、前缀索引
前缀索引顾名思义,定义字符串的一部分内容当作索引,而不是把整个字符串都当作索引。默认的,如果我们创建索引的语句不指定前缀的长度的时候,那么这个索引就会包含整个字符串。
6、主键索引、二级(辅助)索引
- 主键索引:主键自带索引,在表中建立主键的同时,会按照主键的次序来将数据进行排序。
- 二级索引:一张表原来有索引,又添加了一个新的索引,这个新添加的索引就是二级索引
三、MySQL管理索引
创建索引
-- 两种方式
-- 如果选择作为索引的字段是一个字符串,可以只取这个字符串的一部分
create index index_name on tb_name(col_name[(length)])
alter table tb_name add index index_name(col_name)
-- 执行例子
mysql> create index index_name on students(name(5));
Query OK, 0 rows affected (0.52 sec)
Records: 0 Duplicates: 0 Warnings: 0
#name(5)表示使用name这个字段来作为索引值,但是只取name这个字符串的前五个字符
删除索引
-- 两种方式
drop index index_name on tb_name
alter table tb_name drop index index_name(col_name)
-- 执行例子
mysql> create index index_name on students(name(5));
Query OK, 0 rows affected (0.52 sec)
Records: 0 Duplicates: 0 Warnings: 0
#name(5)表示使用name这个字段来作为索引值,但是只取name这个字符串的前五个字符
查看索引
show index from tb_name
mysql> show index from students;
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| students | 0 | PRIMARY | 1 | StuID | A | 25 | NULL | NULL | | BTREE | | |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
table:当前执行操作的表名
Non_unique:是否是唯一键索引
Key_name:索引名,说明是主键索引
Column_name:建立索引的字段
Index_type:索引类型,B+树
四、explain工具
explain可以用来判断是否使用了索引,显示执行的细节
mysql> explain select * from students where stuid=20;
+----+-------------+----------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | students | const | PRIMARY | PRIMARY | 4 | const | 1 | NULL |
+----+-------------+----------+-------+---------------+---------+---------+-------+------+-------+
1 row in set (0.00 sec)
id:执行编号,标识select所属的行。如果在语句中没子查询或关联查询,只有唯一的select,每行都将显示1
select_type:查询类型,simple是简单查询。复杂查询:PRIMARY
table:当前正在操作的表
type:表示的是访问类型。 all:全表扫描(表从头到位扫描一遍) ref:表示参考了索引来进行查找
possible_keys:可以使用的索引
key:显示mysql决定采用哪个索引来优化查询
key_len:显示mysql在索引里使用的字节数
ref:当使用索引列等值查询时,与索引列进行等值匹配的对象信息
rows:为了找到所需的行而需要读取的行数,估算值,不精确
extra:附加信息
MySQL很智能,如果发现利用索引的效率还没有不利用索引的效率高,就会选择不利用索引。
五、profile工具
显示sql语句执行的详细过程
set profiling = ON; #设置这个变量的值为ON默认就开启了这个工具
mysql> select @@profiling;
+-------------+
| @@profiling |
+-------------+
| 1 |
+-------------+
1 row in set, 1 warning (1.60 sec)
开启以后通过:
mysql> show profiles;
可以看到曾今执行过的命令以及花费的时间。
mysql> show profiles;
+----------+------------+------------------------+
| Query_ID | Duration | Query |
+----------+------------+------------------------+
| 1 | 1.63420125 | select @@profiling |
| 2 | 0.00017425 | select * from students |
+----------+------------+------------------------+
2 rows in set, 1 warning (0.00 sec)
#显示语句的详细执行步骤和时长
Show profile for query num
mysql> Show profile for query 1;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000040 |
| checking permissions | 1.634089 |
| Opening tables | 0.000010 |
| init | 0.000008 |
| optimizing | 0.000004 |
| executing | 0.000008 |
| end | 0.000003 |
| query end | 0.000003 |
| closing tables | 0.000003 |
| freeing items | 0.000016 |
| cleaning up | 0.000019 |
+----------------------+----------+
11 rows in set, 1 warning (0.10 sec)