mysql 字典索引_【大白话mysql】你真的了解 mysql 索引吗?

本文来源于公众号: 跬步匠心

什么是索引?

当我们使用汉语字典查找某个字时,我们会先通过拼音目录查到那个字所在的页码,然后直接翻到字典的那一页,找到我们要查的字,通过拼音目录查找比我们拿起字典从头一页一页翻找要快的多,数据库索引也一样,索引就像书的目录,通过索引能极大提高数据查询的效率。

索引的实现方式

在数据库中,常见的索引实现方式有哈希表、有序数组、搜索树。

哈希表

哈希表是通过键值对(key-value)存储数据的索引实现方式,可以将哈希表想象成是一个数组,将索引通过哈希函数计算得到该行数据在数组中的位置,然后将数据存到数组中,容易发现一个问题,如果两个索引通过哈希函数计算后得到的数组位置相同要怎么办?我们可以采用哈希链表,数组的每个 value 都是一个链表,新数据直接添加到链表尾部。

8e0803c1627619a4fa8e19d2f62102d1.png 所以数据库查询过程为:索引通过哈希函数计算数据所在位置 --> 遍历指定位置的链表,找到满足条件的数据。

每次有新数据加入时,新数据时直接添加到链表尾部,所以添加数据时很方便。

哈希表不擅长进行区间查询,一般都用于等值查询,因为两个相邻索引通过 hash 函数后计算得到的数组位置不一定还保持相邻,需要哈希多次才能把区间的数据全查出来。

有序数组

顾名思义,有序数组是按索引大小将数据保存在一个数组上,因为该数组是有序的,可以通过二分法很容易查到位置,找到第一个位置后,通过向左或者向右遍历很容易得到所求区间的数据。因此,无论是等值查询还是区间查询,效率都极高。

但缺陷也是显而易见的,当向数组中间 n 位置插入一条数据时,需将 n 后面的数据全部往后移动,所以,这种索引一般用于静态存储引擎。

搜索树

二叉搜索树:一棵空树,或者是具有下列性质的二叉树:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;二叉搜索树的左、右子树也分别为二叉搜索树。

平衡二叉树:平衡二叉树是在二叉搜索树的基础上引入的,指的是结点的左子树和右子树的深度差不超过 1。

多叉树:每个结点可以有多个子结点,子节点的大小从左到右依次递增。

数据库一般使用平衡树来当索引的存储数据结构,当使用平衡二叉实现索引时,结构如下图。

09c4be0392d08ab08e4dd31e9966d783.png 从图中可发现,每次查询最多需要访问 4 个节点必能得到所要数据。例如查询 user2 时,查询过程为:userA-->userC-->userF-->user2。所以查询速度很高,复杂度为 O (log (n));平衡二叉树的更新复杂度也为 O (log (n))。

区间查询时,由于搜索树的特性(左子树小于右子树),可以很快的排除掉不满足条件的节点,查起来速度也是很快的。

思考下为什么用平衡搜索树呢?

因为普通的二叉树可能因为插入的数据最后变成一个很长的链表,查询复杂度退化成 O (n)。

如果搜索树存于内存中,与多叉树相比,二叉树的搜索速率是最高的,但实际上数据库使用的是 n 叉树而不是二叉树。

索引不仅存于内存,还是写到磁盘上,搜索树上的每个结点在磁盘上表现为一个数据块。

多叉树每个结点下可以有多个子节点,所以存储相同数据量时多叉树的树高比二叉树小,查询一个数据需要访问的结点数更少,即查询过程访问更少的数据块。查询速度较高。

在 mysql 的 innodb 引擎中,使用 B + 树来存储数据,B + 树是一种多叉平衡查找树。

innodb 的索引模型

在 B + 树中,我们将节点分为叶子结点和非叶子结点,非叶子结点上保存的是索引,而且一个节点可以保存多个索引;数据全部存于叶子结点上,并且叶子结点之间通过指针连接起来。

根据叶子结点的内容不同,innodb 索引分为主键索引和非主键索引。非主键索引也称为二级索引。主键索引的叶子结点中保存的数据为整行数据,而非主键索引叶子节点保存的是主键的值。

26db9067febdcbf027a9b9035fe8efe9.png

540891afa36077470ada88f07d3890b8.png 通过主键索引查询数据时,我们只需查找主键索引树便可以获取数据;通过非主键索引查询数据时,我们先通过非主键索引树查找到主键值,然后再在主键索引树搜索一次,这个过程称为回表,也就是说非主键索引查询会比主键查询多搜索一棵树。所以我们应尽可能使用主键查询。

B + 树是一颗 N 叉树,N 是由什么决定的?能否调整?

通过修改 page 的大小来间接调整 N 的大小。一个节点上的所有数据都在一个 page 中,页越大,每页存放的索引就越多,N 就越大。数据页调整后,如果数据页太小层数会太深,数据页太大,加载到内存的时间和单个数据页查询时间会提高,需要达到平衡才行。

修改索引的大小。每个索引包括固定字节数的 Point 指针和索引字段内容,索引字段越小,每页能存的索引就越多,N 就越大。

索引维护

添加新行时,将会在索引表上添加一条记录,如果是索引递增插入时,数据都是追加在当前最大索引之后,不会对树中其他数据造成影响;如果新加入的数据的索引值位于节点的中间,需要挪动部分节点的位置,从而保持索引树的有序性。

而且,相邻多个节点是存储在同一个数据页上的,此时,如果是在已经存储满状态的数据页中插入节点,会申请新的数据页,将部分数据挪动到新的数据页,这个过程称为页分裂,页分裂除了会影响性能,还会降低磁盘空间利用率。不规则数据插入时,会造成频繁的页分裂。所以,一般情况下会采用递增主键,使新数据递增插入。

当相邻两个页由于删除了数据,利用率很低之后,会将数据页做合并。

什么情况下应该使用业务逻辑字段做主键?有什么优缺点?

业务逻辑字段不容易保证索引树结点有序插入,这样写入成本较高。

innodb 默认使用整数类型作为主键,主键长度较小,二级索引的叶子结点中保存的是主键值,主键长度越小,二级索引的叶子结点占用空间也就越小。

当然,使用业务逻辑字段做主键也有好处,可以避免回表,每次只需扫描一次主键索引树即可。

综上,从性能和存储空间方面考量,自增主键往往是更合理的选择,但是当业务场景有且只有一个索引,而且该索引为唯一索引时,此时更适合使用业务逻辑字段作为主键,一个是避免回表,还有一个是只有一个索引也不需要考虑二级索引的空间占用情况了。

索引重建

因为数据修改、删除、页分裂等原因,会导致数据页空间利用率降低,此时,可以考虑重建索引,将数据按顺序插入,提高磁盘空间利用率。

重建普通索引时,直接先删除索引,再重新创建即可。

alter table T drop index k;

alter table T add index(k);

复制代码

主键索引不能通过上面的语句去重建,因为删除主键索引后,innodb 会如下处理:

如果存在非空且字段类型为数值的唯一索引(INT and NOT NULL and UNIQUE INDEX), 会将第一个满足条件的索引作为主键索引 , _rowid 为对应主键,值与唯一索引相同。(可通过 select _rowid from table 查询)。

如果找不到合适的索引,那么 InnoDB 会自动生成一个不可见的名为 ROW_ID 的列名为 GEN_CLUST_INDEX 的主键索引,该列是一个 6 字节的自增数值,随着插入而自增。

所以删除主键索引的结果其实是修改了主键字段,而普通索引的叶子节点存的是主键的值,所以,一旦修改了主键字段,普通索引也会有影响,叶子节点的值将被修改成新的主键字段。

当主键索引需要重建时,更好的做法是直接使用 alter table t engine=innodb 重建表。

写在最后

喜欢本文的朋友,欢迎关注公众号「跬步匠心」,专注大白话分享实用技术

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/428442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java菜单面板设置完能关闭_用Java创建一个屏幕外框架(或者:当所有应用程序窗口关闭时,如何避免Mac上的空白菜单)?...

你一定要考虑WizardOfOdds非常有用的答案.正确使用“The Application Menu”将有所帮助,并且很容易设置最小的Info.plist开始.持久的文件菜单将允许您的应用程序在其他人关闭时打开一个新窗口.这个answer链接到一个简单的example.虽然Apple的Human Interface Guidelines是您用户…

mysql使用jtable_jtable 的简单使用

做后台管理管理系统时,基于ajax的数据操作和富有表现力的数据绑定插件jtable绝对是一个不错的选择,他接收来自服务器端的json格式的数据。而且他是一款开源的基于jquery和jquery ui的插件,您可以根据自己的需要修改其表现,如css&a…

java正则表达 w_正则表达式[\s\S] 与[\w\W]这样的用法,比较.

更新时间:2020年03月04日 17:29:41 投稿:mdxy-dxy很多人咨询[\s\S]*与[\w\W]* 什么意思,不是有.了吗,那么它们的组合,表示所有的都匹配,与它相对应的,有[\w\W]等,意义完全相同,需要…

dalvik虚拟机与Java区别_05 Android---java虚拟机跟dalvik虚拟机的区别(从01开始点点入门,视频+笔记)...

大家好,我是森森这节课我简单给大家介绍一下java虚拟机跟安卓系统虚拟机的区别.可能时间太晚了,有点不在状态,也有点紧张,大家见谅.05java虚拟机跟dalvik虚拟机的区别这篇文章重点写一写安卓运行时和Java运行时的区别.什么是运行时呢?其实我们所说的虚拟机就是运行时.两种虚拟…

java自定义菜单跳转页面_微信公众号开发 自定义菜单跳转页面并获取用户信息实例详解...

微信公众号开发 自定义菜单请先读完本文再进行配置开发请先前往微信平台开发者文档阅读“网页授权获取用户基本信息”的接口说明在微信公众账号开发中,往往有定义一个菜单,然后用户点击该菜单就进入用户个人中心的功能,通常应用于各个公众账号…

团队项目冲刺第一阶段03

回顾昨天:用了各种FQ软件下载SDK,最后终于在11点半后成功加载出helloworld 今天的任务:学习安卓数据库,实现对数据库信息的添加转载于:https://www.cnblogs.com/cairsha/p/8084694.html

java 解析xls 文件_java简单解析xls文件的方法示例【读取和写入】

本文实例讲述了java简单解析xls文件的方法。分享给大家供大家参考,具体如下:读取:import java.io.*;import jxl.*;import jxl.write.*;import jxl.format.*;class Aa{public static void main(String args[]) {try{Workbook workbook null;t…

$(document).ready()和window.onload之间的差异

最近使用$(document).ready(function(){})遇到一个问题:加载页面后发送数据请求后台,得到的数据不对,后发现请求后台时,发送的数据为空,没有获取到值导致的。------改成window.onload function(){}或者$(window).load…

用java做出长方体的表面积_计算长方体、四棱锥的表面积和体积(Java)acm.sdut...

Problem Description计算如下立体图形的表面积和体积。从图中观察,可抽取其共同属性到父类Rect中:长度:l 宽度:h 高度:z在父类Rect中,定义求底面周长的方法length( )和底面积的方法area( )。定义父类Rect…

贝叶斯理论基础理解

从贝叶斯方法谈到贝叶斯网络: http://blog.csdn.net/zdy0_2004/article/details/41096141 1 思考模式 比如往台球桌上扔一个球,这个球落会落在何处呢?如果是不偏不倚的把球抛出去,那么此球落在台球桌上的任一位置都有着相同的机…

java mongodb 关闭连接_如何在mongodb上使用java驱动程序保持连接池关闭?

我正在从java驱动程序2.12.3升级到3.3.0.奇怪的是,收集池似乎突然“起作用”.我的设置如下:Connection在主线程中建立:mongoClient new MongoClient(new MongoClientURI("mongodb://localhost:27017"));mongoClient.setWriteConcern(new Writ…

再论递归

再论递归 大概是从汉诺塔hanoi了解递归算法的: function hanoi(n, a, b, c) {if(n1) {console.log(${a} ---> ${c})return}hanoi(n-1, a, c, b);hanoi(1, a, b, c);hanoi(n-1, b, a, c); }hanoi(10, A, B, C); 我自诩脑回路清奇,然而面对这层层递归&a…

flock lock ex php,php – flock有可能用LOCK_EX返回false吗?

标签:phpBy default, this function will block until the requested lock isacquired在下面我发现了以下示例代码:$fp fopen("/tmp/lock.txt", "r");if (flock($fp, LOCK_EX)) { // acquire an exclusive lockftruncate($fp, 0); …

C++如何实现DNS域名解析转

C如何实现DNS域名解析 这片文章介绍了C如何实现DNS域名解析,还有对相关技术的介绍,代码很详细,需要的朋友可以参考下一、概述 现在来搞定DNS域名解析,其实这是前面一篇文章C实现Ping里面的遗留问题,要干的活是ping的过程中画红线的…

PHP程序中时间戳,php 时间戳常用代码

echo strtotime(date(Y-m-d));获取明天凌晨的时间戳代码:echo strtotime(date(Y-m-d,strtotime(1 day)));附上测试代码:echo strtotime(2012-11-2);echo strtotime(2012-11-2 00:00:00);echo strtotime(date(Y-m-d)),;echo date(Y-m-d H:i:s,strtotime(d…

Echarts入门

引用Echarts 方法1&#xff1a;下载echarts.js后&#xff0c;进行引用&#xff0c;如 <script src"echarts.min.js"></script> 方法2&#xff1a;在线引用&#xff0c;在线网址可为 http://echarts.baidu.com/dist/echarts.min.js R语言中有相应的R包…

高等代数第3版下 [丘维声 著] 2015年版_2020年成人高考 专升本 高等数学复习攻略...

成人高考的高等数学考试按照专业属性分为理工类和经管类&#xff0c;高等数学一直是成考中的比较不好拿分的科目&#xff0c;也是大家复习备考的难点。今天&#xff0c;小编给大家分享一些答题技巧和必备的公式&#xff0c;帮助大家一起来搞定高等数学&#xff0c;希望这份资料…

java虚拟机10.内存模型与线程

多任务处理在现代计算机操作系统中是一项必备的功能&#xff0c;让计算机同时去做几件事情&#xff0c;不仅是因为计算机的运算能力强大了&#xff0c;更重要的原因是计算机的运算速度与它的存储和通信子系统速度的差距太大&#xff0c;大量的时间都花费在磁盘I/O&#xff0c;网…

php仿微信上传图片压缩,PHP仿微信多图片预览上传实例代码

生产图片区域&#xff0c;上传按钮#btn可替换自己想要的图片plupload上传var uploader new plupload.Uploader({//创建实例的构造方法runtimes: html5,flash,silverlight,html4, //上传插件初始化选用那种方式的优先级顺序browse_button: btn, // 上传按钮url: "ajax.php…

笔记本电脑如何保养_嘉兴专业笔记本电脑喷漆加工厂价格实惠

嘉兴专业笔记本电脑喷漆加工厂价格实惠 [xznugcbx]不宜大量储存或久存&#xff0c;做好通风设施。自喷漆如果大量泄露操作人员应迅速撤离泄露污染区人员到安全区域&#xff0c;因罐内的二甲醚气体具有轻微的毒性&#xff0c;并将污染区域进行隔离&#xff0c;罐内的气体跟空气中…