谈谈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 语言相关框架的掌握,更需要对各种 ...
随机推荐
- 在docker中写个Hello World
Hello World Docker 示例 准备hello.cpp #include<stdio.h> int main(){ printf("Hello World Docke ...
- Java历史[史上最详细的阐述了Java发展的历史过程]
Java历史 学习Java语言之前,我觉得大家应该是从头开始,对吧?不管你之前是学过还是没学过,都和学习某一个知识一样,从头开始去了解它,然后到这个深入的掌握,到最后你可能理解并且灵活的运用.所以它肯 ...
- 回文树(回文自动机)(PAM)
第一个能看懂的论文:国家集训队2017论文集 这是我第一个自己理解的自动机(AC自动机不懂KMP硬背,SAM看不懂一堆引理定理硬背) 参考文献:2017国家集训队论文集 回文树及其应用 翁文涛 参考博 ...
- SmartMS如何使用二次验证码/虚拟MFA/两步验证/谷歌身份验证器?
一般点账户名——设置——安全设置中开通虚拟MFA两步验证 具体步骤见链接 SmartMS如何使用二次验证码/虚拟MFA/两步验证/谷歌身份验证器? 二次验证码小程序于谷歌身份验证器APP的优势 1.无 ...
- Dubbo的负载均衡算法源码分析
Dubbo提供了四种负载均衡:RandomLoadBalance,RoundRobinLoadBalance,LeastActiveLoadBalance,ConsistentHashLoadBala ...
- Java线程的6种状态及切换
Java中线程的状态分为6种. 1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法.2. 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running) ...
- vue学习(十三) 删除对象数组中的某个元素
//html <div id="app"> //v-for循环就不写了 每一条数据最后都有一个删除的超链 .prevent阻止默认的跳转行为 只执行点击事件 <a ...
- vue -电子时钟
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 看完这篇。再也不怕被问 HandlerThread 的原理
HandlerThread是什么 官网介绍 A Thread that has a Looper. The Looper can then be used to create Handlers. No ...
- 02_HTML02
学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"软件测试"获取视频和教程资料! b站在线视频 HTML ...