「mysql」索引
Posted 一个正直的男孩
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「mysql」索引相关的知识,希望对你有一定的参考价值。
文章目录
补充概念1:随机访问与连续访问
随机访问
:数据存储的位置是随机的(类似链表),那么在找数据的时候需要花大功夫
连续访问
:数据存放在一起起(数组),查找不费劲
花的功夫:其实就是时间的消耗
补充概念2:一个进程如何加载到内存
系统/mysql的IO
example1:在800w数据中查找一条数据
仔细看我所标记号的地方
- 你可以看到筛选查找和构建索引在筛选查找效率是差了好多指数倍,那是为啥呢?
- 为啥构建索引花的时间更加的多呢?
预知后事如何请看下集🐶,哈哈哈继续往下看吧
概念理解:
概念1:系统的IO基本单位是4kb(这个是看操作系统)
概念2:mysql的IO基本单位是16kb(page )
那就有一个问题,为啥不和系统IO保持一致?
如过和系统IO的基本单位一致你会发现
效率变低了
(有物理层面上硬件的时间消耗,还有软件层面上的写到os的缓冲区,在写到mysql申请的内存(数据池))
如果mysql IO 单位很大也不好(只需要修改一条数据却直接把整个表加载进来)(占用了大多数的系统资源)
example2:
为啥我是无序插入,但是到数据库就有序了呢?
简单理解效率高,有序查找的效率比较低 (后文介绍mysql如何对数据的增删改查)
page的介绍
先看page的结构:
请问一个数据库的数据是否会变多?
答案肯定毋庸置疑,一定会。变多导致的后果是啥呢? 一定是在mysql的
buffer pool
(简单理解一个内存空间) 中有多个page,拿是否需要管理起来呢? 那么管理的本质是啥呢?先描述在组织
,从我给你的page的结构不难看出应该是用双链表的结构
那么现在又有一个比较现实的问题:如何高效的对数据增删改查呢?
查找的本质是啥? 就是如何一次性排出更多的数据
如何curd(增删查改)高效
请问16kb的page都要全部存数据吗????
你把page看做一本书,假如没有目录(但是有页码),你会如何查找呢?一般这种情况是二分查找,但是你使用数据库并不是只需要一条数据,二分就会开始无力,那么就和现实一样给page加一个目录
page的结构
那目录的间隔设置多少才可以效率最高呢?
不知道大家是否有学过希尔排序(默认大家学过),他的间隔越大数据就约无序,一趟下来是复杂度就越低,间隔越小,就约有序,但是复杂度就越高,那么也是同理。
那么还是这个的问题:如果page越来越多了呢,那本质不是还是线性查找吗?如何高效的对数据增删改查呢?
如何解决效率变低的问题
我们依旧在这个目录上做手脚,但不是研究他的间隔。imagine 一下我们可不可以把一个page当作一个数据呢?我们只存每一个page的第一个数据的索引值,那我们不是一次就排出一个page大小的数据了吗?
example:你要找主键索引为2000的数据
老的方法遍历每个page目录差不多需要要找个40~50次吧,但是有了目录page后,便利page目录找到对应的page在便利这个page的目录查找数据,差不多10多次就找到数据了。
或许你还会问如果目录page也太多了呢?那就依葫芦画瓢在上面加一层目录page
浅谈B树与B+
上面介绍的的那个结构其实就是B+树,那B树是咋样的呢?其实也差不多就是效率不一样
请问目录page中是否可以存数据呢?
emmm,也可以啊,好这就是B树哈哈哈是不是很潦草,
且叶子节点的数据不相连
为何B效率没有B+高呢?
从客观层面看我都感觉没啥问题最多就是层数稍微高一点,效率差的不会特别的多。这个不好说在数据量不是特别多的情况下是差不多的。且这个其实不是主要的原因。
主要原因:加载机制
上述的那个B+表请你吧他分离一下目录page和数据page分开,当第一次使用数据库的时候,我先吧目录page加载到buffer pool中,那我需要把全部的page都加载进来吗?不需要。那B树是既存数据又存目录,那么假如数据是在叶子节点那么我不是要把这一条路径下的所有数据都加载到 buffer pool中咯,那就要多次IO。
b树
现在就可以来看为啥给表构建索引的时候效率那么低了
就六字解释:就是在构建B树(目录与目录page)
聚簇索引 VS 非聚簇索引
概念:聚簇叶子节点存的是page,非聚簇的叶子存的是page的地址
注:并没有好坏之分
非(MyISAM)
example:给一列值加索引
非聚簇索引:根据这一列的数据内容构造一个B+树,然后叶子存对应的数据地址
聚簇索引:根据这一列的数据内容构造一个B+树,然后叶子存对应数据在主键的B+树key值(目录值)
主键/唯一/普通 索引
如何创建对应的索引
普通索引的添加方式
ALTER TABLE 表名 ADD INDEX(列名);
CREATE INDEX 索引名 on 表名(列名);
普通索引:
如果需要创建索引,且有重复值那么就用普通索引
查看索引
SHOW KEYS FROM 表名;
DESC 表名;
⚠️注意事项:
- 更新频繁的不适合添加索引(维护B+树需要成本)
- 不要猫猫狗狗都给索引(为了便利而不是负担,一个索引一个B树)
以上是关于「mysql」索引的主要内容,如果未能解决你的问题,请参考以下文章