作者:学Java的冬瓜
博客主页:☀冬瓜的主页🌙
专栏:【MySQL】
分享:纵一苇之所如,凌万顷之茫然。——《赤壁赋》
主要内容:MySQL中索引的介绍、创建索引、使用索引;索引背后的数据结构的分析、关于二叉搜索树、AVL树、B树、B+树这些数据结构分析
文章目录
- 一、索引
- 1、什么是索引?
- 2、索引的优缺点
- 3、使用索引
- @ 查看索引
- @ 创建索引
- @ 删除索引
- 4、总结索引
- 二、重点:索引在MySQL中的数据结构
- 1、数据结构分析
- 2、索引中的数据结构总结
一、索引
1、什么是索引?
可以对表中的一列或者多列创建索引,各类索引有各自的数据结构实现。
原理:当查询某一项时,使用索引后,查询不是从原表中查所有数据再显示目标项,而是将索引拿来查询,数据量大大减少,从而提高查询效率。
2、索引的优缺点
优点:
- 加快了查询操作,提高效率,因为在实际中,查的比增删改多很多。
缺点:
- 索引提高了增删改的开销。因为索引相当于一本书的目录,每次增删改后,需要同时改变这个目录,即改索引。
- 索引会多占用空间
3、使用索引
前提:我创建了一个student表,id为主键,还有一个name字段
mysql> desc student;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
@ 查看索引
创建表时,有主键/unique/外键,都会自动创建索引
-- 查看索引
show index from 表名
mysql> 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 | Visible | Expression |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| student | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
1 row in set (0.04 sec)
@ 创建索引
对于一个非主键,非唯一约束,非外键约束的字段,可以采用普通索引
-- 创建索引
create index 索引名 on 表名(字段名)
mysql> create index ind_name_stu on student(name);
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show index from student;--可以看到,多出了关于name的索引
+---------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+---------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| student | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| student | 1 | ind_name_stu | 1 | name | A | 0 | NULL | NULL | YES | BTREE | | | YES | NULL |
+---------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set (0.04 sec)
@ 删除索引
-- 删除索引
drop index 索引名 on 表名
4、总结索引
- 创建表时,有主键/unique/外键,都会自动创建索引
- 对于一个非主键约束,非唯一约束,非外键约束的字段,可以采用普通索引
- 索引创建好后,查询时会自动使用索引去查,而不需要手动操作。因为SQL是通过数据库的 “执行引擎” 来执行的,这会涉及到 “优化” 操作,即在操作结果不变的前提下,“执行引擎” 去决定是否使用索引,它会选择更优的方法去操作。
- 索引最好在表创建之初就创建好。不然当表中数据量很大很大才创建索引时,会吃掉大量的磁盘IO,花很长时间(几十分钟到几个小时)。并且在这段时间内,数据库无法被正常使用。
- 基于上一条原因,和数据库删库删表一样,索引也是一个危险操作
- 对一个字段有重复内容时,索引可以支持,但是可能不能提高效率,比如我对学生表的性别字段给个索引,不能提高查找效率,这其实是没有意义的。
二、重点:索引在MySQL中的数据结构
1、数据结构分析
哈希表:
- 用哈希表查询元素,时间复杂度为O(1),查找效率极高。但是它在MySQL数据库中有个致命缺陷:它只能比较是否相等,不能进行大于小于这样的范围查询,而数据库经常需要范围查询。
二叉搜索树(BST=>Binary Search Tree):
- 二叉搜索树,又叫二叉排序树。时间复杂度最坏为O(N)(节点个数就是树的高度时最坏)。在二叉搜索树平衡时,即是平衡二叉树(AVL=>AVL是由三个人创建的,取自他们的名字),才是O(logn)(注意:logn是非常高效的,n越大,logn函数图像越平,就越接近O(1))。
- 二叉搜索树可以范围查询,在数据库中可以满足哈希表的缺陷,即实现范围查询(找到起始点和终点就行)。但是二叉搜索树因为是二叉而不是n叉,所以树的高度会比较高,即使它变成平衡的AVL树,而树的高度就代表了查询元素需要的比较次数,在数据库比较元素时,是需要读写硬盘进行IO操作的,所以高度越高,查询效率越低。
N叉搜索树(B树=>Binary Tree):
- 又叫B树(B-Tree),有些人又叫B-树,不是B减树,而是叫做B杠树。例如B+树其实是B±树(B加杠树),因为不美观,所以省掉杠叫做B+树。而B树可以加上杠就是(B-树)。
- 虽然比较次数不变,但是硬盘IO操作减少了。因为从硬盘读取一个节点时,每个节点里面就包含了多个数据,所以减少了硬盘IO操作。下面就是B树的数据结构简图。
B+树:
- 和B树一样,高度降低后,硬盘读写次数减少,效率提高。
- 适合范围查询。 因为B+树的数据都在叶子节点上,并且叶子节点用链表串起来,只要找到起点和终点所在的节点,用链表查询就很方便,所以非常适合范围查询。
- 查询操作比较均衡。 因为所有数据都在叶子节点上用链表连接起来 ,无论查询哪个元素,硬盘IO次数差不多都要到叶子节点。而如果是B树,因为在非叶子节点上的数据也要看,所以对于查询一个数据可能IO次数减少,但查询一个范围的数据时,IO次数会大大增加。
- 因为B+树的非叶子节点不存放数据行,只存放索引,因此空间大大降低,这时,内存可能就可以放下这个结构,进一步降低了硬盘的IO,提高效率。
- 综上所有分析,B+树是非常适合于做数据库的索引背后的数据结构的。
2、索引中的数据结构总结
- 主键索引会随着表的创建而自动创建(如果用B+树实现),当手动创建非主键索引时,会再创建一棵B+树,这棵B+的非叶子节点里面存的都是这一列的key(比如创建name2索引 ),到了叶子节点这一行,存的就不是数据行了,而是存主键(id)。
- 如果使用主键列来索引来查询,只查一次第一棵B+树即可; 而如果用非主键列来查询,要先查一遍这个非主键列索引的B+树,然后再查主键列索引的B+树。
- 回表:就是用非主键列索引在叶子节点查出主键id,在根据id去主键列索引查询数据行。
- MySQL的InnoDB这个主流的数据库引擎,就是使用的B+树。不同的引擎可能使用不同的数据结构。哈希表增删查改效率极高,因此在特定情况下也可能使用哈希表。