谈谈MySql索引
刚刚学习完丁奇老师《MySql 实战 45 讲》专栏中的索引部分,图文并茂的风格解开了我之前的许多疑惑,并且学习到许多新的东西,在此做个笔记,方便后续复习。由于 MySql 中存在多种存储引擎,每种存储引擎的实现方式都不太一样,而 InnoDB 在现在是比较流行的存储引擎,因此以下内容都是基于 InnoDB 讨论的。
索引是如何存储的
InnDB 索引是基于 N叉树实现的,为什么要使用 N叉树而不是二叉树呢?这是因为 MySql 中的数据都是存储在磁盘中的,我们查找数据都要进行 IO 操作,IO 操作比 CPU 运行的速度慢了一个等级,使用二叉树存储数据时,当我们从一个节点出发,要找它的子节点,就得进行一次 IO 操作,当数据库存储的数据多了之后,二叉树的层数变高,进行数据查找时 IO 操作也变多了。为了减少数据查询时的 IO 操作,InnDB 底层是使用 N叉树存储的,这个 N 取决于数据块的大小。
主键索引、非主键索引
上面说到,InnoDB 索引是基于 N叉树实现的,但是一个表我们需要建立的索引个数不止一个,因此每建立一个索引,InnoDB 就会创建一颗 N叉树来维护该索引数据,索引树建立完之后 InnDB 是如何通过索引找出我们所需要的数值的呢?
假设有一张表是这个样子的:
create table T(
id int primary key,
k int not null,
name varchar(16),
index(k))engine = InnDB;
)
这张表显示创建了一个索引 k,还包含一个默认的主键索引 id,InnDB 是按照如下方式来存储这两颗索引树的:

可以看到,主键索引的叶子节点是一个数据块,每个数据块就是一个行记录,包含 id 、k、name 的值,这就叫做主键索引,而索引 k 的叶子节点包含的数据是 id 值,这就是非主键索引。在这个表中,当我们需要根据某个 k 的值查找对应的 name 值,需要先根据 k 的值找出对应的 id 值,再根据 id 值查找对应的数据块,从数据块中才可以得知 name 的值。在 InnDB 里,主键索引也被称为聚簇索引,非主键索引也被称为二级索引。
覆盖索引
上面说到当使用二级索引查找其他字段值时,需要查找两颗索引树才可以找到对应字段的值,这是因为二级索引的叶子节点只包含主键值,如果在二级索引的叶子节点已经包含了我们要查找的内容,那么就可以减少一次查询,提升性能。例如刚刚的那张表,我们需要根据 k 值来找 id,此时二级索引的叶子节点已经包含了我们需要的数据,我们称此为覆盖索引。
我们可以根据具体的业务场景来创建覆盖索引,比如根据身份证 id 查找身份证号这个需求是很常见的,我们就可以给身份证 id 和身份账号建立一个联合索引,这样根据身份证 id 找出来的数据块就包含了身份证号,不用再根据主键去寻找身份证号了。
索引重建
这个是丁奇老师在专栏里面留下的问题:对于上面例子中的 InnDB 表 T,如果要重建索引 k,两个 SQL 语句可以这么写:
alter table T drop indexk;
alter table T add index(k);
如果要重建主键索引,也可以这么写:
alter table T drop primary key;
alter table T add primary key(id);
对于上面两个重建索引的做法,有不合适的地方吗?为什么?有更好的方法吗?
回答:上面的语句中,重建索引 k 的方式合理,但是重建主键的过程不合理。不论是删除主键还是创建主键,都会将整个表重建,所以连着执行两个语句,第一个语句就白做了,这两个语句,可以使用
alter table T engine = InnDB代替。
该索引是否是必须的
这是老师留下的另一个问题:DBA 小吕在入职新公司的时候,就发现自己接手维护的库里面,有这么一个表,表结构定义类似这样的:
CREATE TABLE 'geek' (
`a` int(11) NOT NULL,
`b` int(11) NOT NULL,
`c` int(11) NOT NULL,
`d` int(11) NOT NULL,
PRIMARY KEY (`a`, `b`),
KEY `c` (`c`),
KEY `ca` (`c`, `a`),
KEY `cb` (`c`, `b`)
)
公司的同事告诉他,由于历史原因,这个表需要 a、b 做联合主键,这个小吕理解了。但是,学过本章的内容的小吕又纳闷了,既然主键包含了 a、b 这两个字段,那意味这单独在字段 c 上创建一个索引,就已经包含了这三个字段,为什么要创建 “ca”、“cb” 这两个索引?同事告诉它,是因为他们的业务里面有这样的两种语句:
select * from geek where c=N order by a limit 1;
select * from geek where c=N order by b limit 1;
问题是,这位同事的解释对吗,为了这两个查询模式,这两个索引是否都是必须的?为什么呢?
回答:我们一个一个来分析,首先是主键索引(a、b),主键索引先按照 a 排序,然后按照 b 排序,索引 c 就是按照 c 进行排序,在叶子节点中包含主键,即先按照 c 排序,然后按照 a 排序,接着按照 b 排序。索引 ca 先按照 c 排序,然后按照 a 排序,主键部分包含 b,这样看的话它和索引 c 存储的内容是一样的。索引 cb 先按照 c 排序,然后按照 b 排序,主键部分包含 a。经过上面分析,索引 ca 是可以去掉的,因为它的作用和索引 c 是一样的。
专栏推荐
丁奇老师的这个专栏从底层出发,并且会结合平时的业务场景来讲解 MySql,虽然刚开始没学多久,但是受益匪浅,上面只是我个人的笔记,如果大家有兴趣可以通过下面的二维码去购买对应的课程,学生还有五折哦!

谈谈MySql索引的更多相关文章
- 谈谈MySQL 索引
1.索引是什么 索引(Index)是帮助MySQL高效获取数据的数据结构.我们可以简单理解为:索引的目的在于提高查询效率. 2.原理 索引的数据结构是B+树,原理图如下 关于B+树的详细介绍,可以参见 ...
- 谈谈MySQL的索引
目录 索引 前言 是什么 B树 B+树 B树和B+树结构上异同 有什么用 怎么用 索引 前言 总所周知,数据库查询是数据库的最主要功能之一.我们都希望查询数据的速度能尽可能的快.而支撑这一快速的背后就 ...
- 谈谈MySQL数据表的类型(转)
谈谈MySQL数据表的类型 通常意义上,数据库也就是数据的集合,具体到计算机上数据库可以是存储器上一些文件的集合或者一些内存数据的集合. 我们通常说的MySql数据库,sql server数据库等等其 ...
- 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景?
在日常开发中,尤其是业务开发,少不了利用 Java 对数据库进行基本的增删改查等数据操作,这也是 Java 工程师的必备技能之一.做好数据操作,不仅仅需要对 Java 语言相关框架的掌握,更需要对各种 ...
- 浅谈Mysql索引
文章原创于公众号:程序猿周先森.本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号. 我们都知道,数据库索引可以帮助我们更加快速的找出符合的数据,但是如果不使用索引,Mysql则会从第一条开始查询 ...
- 索引很难么?带你从头到尾捋一遍MySQL索引结构,不信你学不会!
前言 Hello我又来了,快年底了,作为一个有抱负的码农,我想给自己攒一个年终总结.自上上篇写了手动搭建Redis集群和MySQL主从同步(非Docker)和上篇写了动手实现MySQL读写分离and故 ...
- 带你从头到尾捋一遍MySQL索引结构(1)
从一个简单的表开始 create table user( id int primary key, age int, height int, weight int, name varchar(32) ) ...
- 带你从头到尾捋一遍MySQL索引结构(2)
前言 Hello我又来了,快年底了,作为一个有抱负的码农,我想给自己攒一个年终总结.索性这次把数据库中最核心的也是最难搞懂的内容,也就是索引,分享给大家. 这篇博客我会谈谈对于索引结构我自己的看法,以 ...
- 第36讲 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景
在日常开发中,尤其是业务开发,少不了利用 Java 对数据库进行基本的增删改查等数据操作,这也是 Java 工程师的必备技能之一.做好数据操作,不仅仅需要对 Java 语言相关框架的掌握,更需要对各种 ...
随机推荐
- bzoj3858Number Transformation*
bzoj3858Number Transformation 题意: 给一个数n,对其进行k次变换,第i次变换是将当前的n变成大于等于n的最小的i的倍数.求k次变换后n为多少.n≤10^10,k≤10^ ...
- 那些非cmake生成的VTK工程存在的让人崩溃的坑
由于cmake和IDE的一些编译选项不同,所以导致我们使用者需要多做一些事情.而且vtk官方也表示: If you are not using CMake to compile your code, ...
- Vue JSX、自定义 v-model
博客地址:https://ainyi.com/92 最初用到 JSX,就是做这个博客的时候.iview 表格组件,不支持像 element 那样直接写 html 代码渲染,只能通过 render 函 ...
- Ethical Hacking - NETWORK PENETRATION TESTING(18)
Session Hijacking What if the user uses the "remember me" feature? If the user uses this f ...
- vue : history模式与项目部署的爬坑
需求:url不能有#符号,且不放在服务器虚拟主机的根目录. 假设放在虚拟主机的 medicine 文件夹下. 需要改两个文件,一个是 ./config/index.js (vue设置文件) ,另一个是 ...
- canvas使用context.drawImage时图片不在画布上展示的问题
遇到问题:找到图片img元素后,将参数传给context.drawImage(image,10,10)后图片并没有在画布上展示. 解决方案:在外层嵌套document.images[0].onload ...
- python中if及if-else如何使用
if 结构 if 结构允许程序做出选择,并根据不同的情况执行不同的操作 基本用法 比较运算符 根据 PEP 8 标准,比较运算符两侧应该各有一个空格,比如:5 == 3. PEP8 标准 ==(相等) ...
- java 集合区别
TreeMap和TreeSet的区别 相同点: TreeMap和TreeSet都是有序的集合,也就是说他们存储的值都是排好序的. TreeMap和TreeSet都是非同步集合,因此他们不能在多线程之间 ...
- 使用SQL语句建表,插入数据
--选中数据库,点击新建查询,然后执行即可--这是SQL中的注释信息,使用两个减号来注释. drop table Book --删除表Book create table Book --创建表Book ...
- MyBatis动态插入的实现
mybatis通过定义前缀后缀和分割字符来拼接sql语句,实现动态插入的功能 <insert id="addNewsTypeByNewsId"> insert into ...