HR眷恋的数据库高频考题之一 —— 索引
本篇会加入个人的所谓鱼式疯言
❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言
而是理解过并总结出来通俗易懂的大白话,
小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.
🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!
前言
在前几篇文章中,我们主要讲解了关于 数据表的CRUD 的各种 基础操作 , 而本篇文章我们讲继续学习 数据库的索引
索引很重要, 是我们面试中 HR经常问到的很经典``,很热门`的考题之一 。
所以小伙伴们一定要好好理解消化本篇文章哦,说不定你下一次面试的时候,就会遇到这样的考题哦 💖 💖 💖 💖
目录
-
索引的初识
-
索引的不足
-
如何使用SQL 来操作索引
-
索引背后的数据结构
一. 索引的初识
1. 索引的概念
索引的英文名: index
小伙伴们是不是很眼熟,是的,这个英文单词本质上就是我们 Java数组 中常用的 下标 的含义 。
除了这个含义,本质上我们还有一个含义就是 : 目录 。
是的,索引的认识,本质上就是相当于我们 新华词典上的目录
但是索引是针对数据库中的 某一列 来说的,就是说每个不同的列 可以构建 不同的索引 ,
就是我们的新华词典的目录一样,有我们的 拼音目录,部首目录,生僻字目录 等…
居然 索引 相当于 目录 , 我们设想下目录的作用不就是 方便我们查找吗? 那么数据库索引是不是也是如此呢 ? ? ?
2. 索引的作用
索引作用就是 加快我们查找速度,提高我们 查找的效率 。
因为索引是针对 某个列 来说的,所以小伙伴使用时,你要查询的 哪个列 要和 索引 对应的列 相统一,才能触发 索引 的作用,
对于数据库本身来说,索引是有 自动创建 和 手动创建 的
. 自动创建索引
当我们 创建表 时, 凡是以下三种情况就会创建 我们的索引
- 主键索引
-- 创建该表 create table if not exist my_table (id int primary key , name varchar(49)); -- 查看表结构 desc my_table; -- 查看该表的索引 show index from my_table;
像上面这样我们创建 主键 时,就会自动生成该 字段的索引
这里的 show index from my_table;
小编在下面会在 . 如何使用 SQL 来操作索引 中,给小伙伴们细细道来哦 ❣️ ❣️ ❣️ ❣️
小伙伴们只需要知道,这是我们 查询表中索引 的 SQL语句即可哦
- unique 索引
-- 删除前面的表 drop table if exists my_table; # 创建该表 create table my_table ( id int unique , name varchar(45)); -- 查看表结构 desc my_table; -- 查看该表中的索引 show index from my_table;
- 外键索引
-- 创建父表 create table father ( father_id int primary key , name varchar(23)); -- 创建子表并进行外键连接 create table son ( son_id int primary key , name varchar(38), father_id int , foreign key(father_id) references father(father_id)); -- 查看索引 show index from son;
有个问题想问 小伙伴,为什么我们在创建 主键, unique , 外键 时, MySQL会自动添加索引呢 ?
我们可以回归到 unique 和 主键 自身的作用来看 : 他们有一个 共同的作用 就是保持该 字段的数据 是 唯一 的,
为了保证 唯一性, MySQL的底层是需要 进行查询 ,从查询中返回该数据 是否唯一 , 居然用到了查询,那么我们就需要 索引来加快我们的查询速度 。
还有一个就是我们的 外键, 外键的作用就是保证 子表的该字段数据 在 父表的范围 中, 父表的该外键字段数据必须 含有子表 的数据范围
当我们建立好 外键连接 后
如果需要对子表的数据进行 增加 和修改,MySQL自身就会 查询一遍父表 ,看 子表要新添加的数据在子表中 是否存在 ,存在就添加,不存在就无法添加 。
同样当我们需要对父表的数据进行 删除 和 修改 时, 我们就要 查询子表的数据,如果子表中含有该数据,我们就不能对父表和子表中都含有的数据进行 删除和修改
居然都要涉及到 查询, 所以我们MySQL就会对外键自动添加 索引,以此来加快 查询速度 。
关于程序员自身如何 手动创建索引 ,小编在这里就 不剧透 哦,在如何使用SQL 来操作索引 会详细解释哦 💞 💞 💞 💞
鱼式疯言
关于自动创建索引,小编有两点想和小伙伴分享:
- 索引是针对表中 某一个字段 而言的,当我们需要对 某个字段查询 时要和对应 字段索引 相统一
- 像我们 主键,外键, unique 修饰的字段, 他们都涉及到 查询, MySQL都会自动创建 索引 益于 查询速度的加快 。
- MySQL 自动创建的索引 是 不允许删除 的,小编下面也会细细讲解哦
二. 索引的不足
世间万物,凡事都 有好的一面 和 不好的一面 ,居然索引能 加快我们的查询速度 ,必然也要付出一定的代价
不足一
创建索引 时,需要占用 额外的空间.
这就好比我们的新华词典中的目录一样,我们目录也是占用 纸张页数的
不足二
可能会加快 数据表 的 增删改 操作的 执行速度 。
可能会 减慢 数据表的 增删改 操作的 执行速度 。
也可能 不会影响 数据表的 增删改 的操作的 执行速度 。
鱼式疯言
小编在这里解释下哈 💥 💥 💥 💥
delete from 表名 set 列名=新数据 where 条件 ;
-
像我们这里涉及到 查询操作 的时候,就会 加快执行速度
-
像有些 删除 或者 修改 了数据之后, 我们对应的索引就 需要调整 , 就有可能会 触发 多次 硬盘IO , 减慢 执行速度。
-
也有可能和我们索引无关的,就 不影响 我们的执行速度
三. 如何使用SQL 来操作索引
1. 查看当前索引
. SQL语句
show index from 表名 ;
. 语句分析
查询索引的关键标识是 show index 后面再配上表名即可 。
. 注意事项
虽然和我们查询 数据库 和 数据表 中的 show 很像, 但是我们需要注意一点是 查询当前 数据库和数据表 是需要 再后面加上 S 的 ,而我们的 索引 是 不需要的 。
2. 创建索引
在上面的内容中,小编主要讲解了 数据表中 自动创建索引 的内容, 而这里要重点我们程序员本身用 SQL 手动创建索引 的方式
. SQL语句
create index 索引名 on 表名(列名);
. 语句分析
需要创建索引时, 标识关键字 create index 跟上索引名, 并用 on 来连接。
这和我们 创建表 和 创建数据库 不同的是, 因为我们的索引是针对 列 而已的,所以我们需要用 on 指定对应 表中的列 来 创建 我们的索引 。
. 注意事项
对于索引本身来说是 利大于弊 的 ,但是对于 手动创建索引 来说,其实有些情况是一种 危险 的操作 。
当数据表是 空 表或者是 只有 几千行几万行 数据时, 我们再 创建索引的 影响不大的 。
但是当我们数据表中存放上 百万行,千万行数据 时, 如果再去 创建索引 时,就会触发 硬盘上大量的 IO , 这样会导致整个 数据库 直接挂掉 。
这样的操作就相当于给正在飞的飞机换发动机 ,这是一个 非常危险 的操作 。
所以当我们需要在数据表中存储的 数据规模非常大 的时候, 就需要对数据库的用 哪些列 创建索引, 有一个具体的 规划和预测 ,以免出现 大量数据 ,当 创建数据库 就会 触发 大量硬盘 IO 。
3. 删除索引
. 语句分析
drop index 索引名 on 表名;
. 语句分析
删除索引 的标志关键字就是 drop index ,因为 索引名不同表的可能一样 , 所以我们需要注意后面用 on 来指定指定 对应的表
. 注意事项
这里需要 注意的一点 就是 :
- 小伙伴们手动自己创建的 索引 是可以删除的,但是 MySQL自动生成的索引 是 无法删除的 。
- 删除索引也是一个 非常危险 的操作,和我们上面的 创建索引 一样,当 数据规模很大 时,这种操作是相当于给 正在飞的飞机上拆发动机 。
所以小伙伴一定要考虑好 何时删除索引 才是解决之道哦
四. 索引背后的数据结构
1. 索引背后数据结构的探讨
小伙伴可以猜想下我们索引背后是哪有一种神秘的 数据结构做支持 ,才能达到像 书的目录 一样 , 能 加快 我们 查询的速度 。
说到小伙伴学过的关于有查找功能的数据结构无非就是 以下两个 :
二叉搜索树 : 我们知道对于 普通的二叉搜索树 来说, 一般都不是平衡二叉树,这样就会导致我们的时间复杂度最坏能达到 O(N) , 对于硬盘来说 O(N) 级别的时间复杂度 可 比 内存中 O(N) 的时间复杂度还大的多很多 。
并且对于二叉树来说 , 如果数据规模很大,树的高度就 很高 ,经历的 硬盘 IO 次数也是 很大 的 , 就会大幅度 减慢 查询速度 。
所以二叉搜索树是不适合做我们数据结构背后的索引
哈希表 : 哈希表的本质是讲一组 key 值 通过 哈希函数 转化为我们 数组的下标 进行存储 ,但是这个也只能 查找某个值 ,对于 我们 SQL x > m 这种范围查找, Hash(x) > Hash(m) 这种 结果并不成立 的 。 所以也不适合用作我们 索引的数据结构 。
那么会是哪种数据结构呢? 答案就是我们的 B + 树 …
可以这么说 ,我们的 B + 树 是专门为 数据库索引 量身定做的一种特殊的数据结构 。
2. B+ 树的特点
- B+树 本身是一个N 叉搜索树, 一个节点上 有 N 个度
- 每个节点都有 多个 K 值, 而有 多少个 K 就把 划分了 多少段区域 ,就有多少个 子节点 。
- K 为父节点 ,下放到 子节点 时,是作为该节点的 最大的 K
- B+ 树的叶子节点 ,是该 数据表的全集 ,并且 通过 链式结构 来连接每一个叶子节点
- 叶子节点存储的数据表中的每一行 , 非叶子结构存储的是 索引列 的K .
3. B+ 树的优势
-
因为 B+ 树 本身是 N叉树 ,所以有效的 降低了 树的高度,从而 减少 经历 硬盘IO 次数。
-
B+ 树中每个节点存储的是多个K , 先让 硬盘读取该节点 ,然后在内存进行比较 ,这样就可以有效的 减少 经历硬盘IO的次数。
-
叶子节点因为是 数据的全集 ,这样经历硬盘的次数和比较的次数相当,能够更稳定预估结果
-
一个个叶子节点 是由 链表 来连接的,当我们 查找某个范围 时, 就可以利用链式结构 快速查找 该范围的区间 。
-
叶子节点是存储数据表中的 每一行 ,但非叶子节点存储的是 索引列的 K , 就可以 减少 每个节点的 存储空间,甚至让内存来读取数据 。
鱼式疯言
在这里小编最后想提及一个小概念
-
对于我们平常 学习的 数据库 , 数据表 ,以及本篇文章学习的 索引 , 本质上只是一种逻辑结构,而不是我们真正意义上的 表 或者 目录 .
-
真正提的上 物理结构 的,那便是我们的 数据结构 , 所以说我们的数据库的这种 逻辑结构 的背后是需要数据结构这样的物理结构作为支持的
-
数据库本身就是一种 “客户端” - “服务器” 结构的程序 。
总结
- 索引的初识 :
我们知道对于索引就是一本书特殊的 “目录” ,能加快查询的速度
但需要注意的是,我们的索引是针对列而已的,我们指定列查询一定要和索引列一一对应才能, 索引的查询效果才能生效。
并且MySQL会对 主键,unique , 外键 的自动生成索引, 且不能删除 。
- 索引的不足 :
唯一两点不足就是 :
-
占有额外的空间
-
可能会影响增删改的速度
-
- 索引的不足 :
-