刚刚学习完丁奇老师《MySql 实战 45 讲》专栏中的索引部分,图文并茂的风格解开了我之前的许多疑惑,并且学习到许多新的东西,在此做个笔记,方便后续复习。由于 MySql 中存在多种存储引擎,每种存储引擎的实现方式都不太一样,而 InnoDB 在现在是比较流行的存储引擎,因此以下内容都是基于 InnoDB 讨论的。

索引是如何存储的

InnDB 索引是基于 N叉树实现的,为什么要使用 N叉树而不是二叉树呢?这是因为 MySql 中的数据都是存储在磁盘中的,我们查找数据都要进行 IO 操作,IO 操作比 CPU 运行的速度慢了一个等级,使用二叉树存储数据时,当我们从一个节点出发,要找它的子节点,就得进行一次 IO 操作,当数据库存储的数据多了之后,二叉树的层数变高,进行数据查找时 IO 操作也变多了。为了减少数据查询时的 IO 操作,InnDB 底层是使用 N叉树存储的,这个 N 取决于数据块的大小。

主键索引、非主键索引

上面说到,InnoDB 索引是基于 N叉树实现的,但是一个表我们需要建立的索引个数不止一个,因此每建立一个索引,InnoDB 就会创建一颗 N叉树来维护该索引数据,索引树建立完之后 InnDB 是如何通过索引找出我们所需要的数值的呢?

假设有一张表是这个样子的:

  1. create table T(
  2. id int primary key,
  3. k int not null,
  4. name varchar(16),
  5. index(k))engine = InnDB;
  6. )

这张表显示创建了一个索引 k,还包含一个默认的主键索引 id,InnDB 是按照如下方式来存储这两颗索引树的:

可以看到,主键索引的叶子节点是一个数据块,每个数据块就是一个行记录,包含 id 、k、name 的值,这就叫做主键索引,而索引 k 的叶子节点包含的数据是 id 值,这就是非主键索引。在这个表中,当我们需要根据某个 k 的值查找对应的 name 值,需要先根据 k 的值找出对应的 id 值,再根据 id 值查找对应的数据块,从数据块中才可以得知 name 的值。在 InnDB 里,主键索引也被称为聚簇索引,非主键索引也被称为二级索引

覆盖索引

上面说到当使用二级索引查找其他字段值时,需要查找两颗索引树才可以找到对应字段的值,这是因为二级索引的叶子节点只包含主键值,如果在二级索引的叶子节点已经包含了我们要查找的内容,那么就可以减少一次查询,提升性能。例如刚刚的那张表,我们需要根据 k 值来找 id,此时二级索引的叶子节点已经包含了我们需要的数据,我们称此为覆盖索引

我们可以根据具体的业务场景来创建覆盖索引,比如根据身份证 id 查找身份证号这个需求是很常见的,我们就可以给身份证 id 和身份账号建立一个联合索引,这样根据身份证 id 找出来的数据块就包含了身份证号,不用再根据主键去寻找身份证号了。

索引重建

这个是丁奇老师在专栏里面留下的问题:对于上面例子中的 InnDB 表 T,如果要重建索引 k,两个 SQL 语句可以这么写:

  1. alter table T drop indexk;
  2. alter table T add index(k);

如果要重建主键索引,也可以这么写:

  1. alter table T drop primary key;
  2. alter table T add primary key(id);

对于上面两个重建索引的做法,有不合适的地方吗?为什么?有更好的方法吗?

回答:上面的语句中,重建索引 k 的方式合理,但是重建主键的过程不合理。不论是删除主键还是创建主键,都会将整个表重建,所以连着执行两个语句,第一个语句就白做了,这两个语句,可以使用 alter table T engine = InnDB 代替。

该索引是否是必须的

这是老师留下的另一个问题:DBA 小吕在入职新公司的时候,就发现自己接手维护的库里面,有这么一个表,表结构定义类似这样的:

  1. CREATE TABLE 'geek' (
  2. `a` int(11) NOT NULL,
  3. `b` int(11) NOT NULL,
  4. `c` int(11) NOT NULL,
  5. `d` int(11) NOT NULL,
  6. PRIMARY KEY (`a`, `b`),
  7. KEY `c` (`c`),
  8. KEY `ca` (`c`, `a`),
  9. KEY `cb` (`c`, `b`)
  10. )

公司的同事告诉他,由于历史原因,这个表需要 a、b 做联合主键,这个小吕理解了。但是,学过本章的内容的小吕又纳闷了,既然主键包含了 a、b 这两个字段,那意味这单独在字段 c 上创建一个索引,就已经包含了这三个字段,为什么要创建 “ca”、“cb” 这两个索引?同事告诉它,是因为他们的业务里面有这样的两种语句:

  1. select * from geek where c=N order by a limit 1;
  2. 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索引的更多相关文章

  1. 谈谈MySQL 索引

    1.索引是什么 索引(Index)是帮助MySQL高效获取数据的数据结构.我们可以简单理解为:索引的目的在于提高查询效率. 2.原理 索引的数据结构是B+树,原理图如下 关于B+树的详细介绍,可以参见 ...

  2. 谈谈MySQL的索引

    目录 索引 前言 是什么 B树 B+树 B树和B+树结构上异同 有什么用 怎么用 索引 前言 总所周知,数据库查询是数据库的最主要功能之一.我们都希望查询数据的速度能尽可能的快.而支撑这一快速的背后就 ...

  3. 谈谈MySQL数据表的类型(转)

    谈谈MySQL数据表的类型 通常意义上,数据库也就是数据的集合,具体到计算机上数据库可以是存储器上一些文件的集合或者一些内存数据的集合. 我们通常说的MySql数据库,sql server数据库等等其 ...

  4. 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景?

    在日常开发中,尤其是业务开发,少不了利用 Java 对数据库进行基本的增删改查等数据操作,这也是 Java 工程师的必备技能之一.做好数据操作,不仅仅需要对 Java 语言相关框架的掌握,更需要对各种 ...

  5. 浅谈Mysql索引

    文章原创于公众号:程序猿周先森.本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号. 我们都知道,数据库索引可以帮助我们更加快速的找出符合的数据,但是如果不使用索引,Mysql则会从第一条开始查询 ...

  6. 索引很难么?带你从头到尾捋一遍MySQL索引结构,不信你学不会!

    前言 Hello我又来了,快年底了,作为一个有抱负的码农,我想给自己攒一个年终总结.自上上篇写了手动搭建Redis集群和MySQL主从同步(非Docker)和上篇写了动手实现MySQL读写分离and故 ...

  7. 带你从头到尾捋一遍MySQL索引结构(1)

    从一个简单的表开始 create table user( id int primary key, age int, height int, weight int, name varchar(32) ) ...

  8. 带你从头到尾捋一遍MySQL索引结构(2)

    前言 Hello我又来了,快年底了,作为一个有抱负的码农,我想给自己攒一个年终总结.索性这次把数据库中最核心的也是最难搞懂的内容,也就是索引,分享给大家. 这篇博客我会谈谈对于索引结构我自己的看法,以 ...

  9. 第36讲 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景

    在日常开发中,尤其是业务开发,少不了利用 Java 对数据库进行基本的增删改查等数据操作,这也是 Java 工程师的必备技能之一.做好数据操作,不仅仅需要对 Java 语言相关框架的掌握,更需要对各种 ...

随机推荐

  1. java的干儿子锁Lock

    目录 Lock的由来 线程之间的交互 Lock方法简介 lock() lockInterruptibly() trylock() trylock(long,TimeUnit) unlock() new ...

  2. 【JVM之内存与垃圾回收篇】类加载子系统

    类加载子系统 概述 完整图如下: 如果自己想手写一个 Java 虚拟机的话,主要考虑哪些结构呢? 类加载器 执行引擎 类加载器子系统作用 类加载器子系统负责从文件系统或者网络中加载 Class 文件, ...

  3. 微信扫码登陆js

    先贴一个微信开发文档教程 https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.ht ...

  4. 七牛云如何绑定二次验证码_虚拟MFA_两步验证_谷歌身份验证器?

    一般情况下,点账户名——账户设置——安全设置,即可开通两步验证 具体步骤见链接  七牛云如何绑定二次验证码_虚拟MFA_两步验证_谷歌身份验证器?   二次验证码小程序(官网)对比谷歌身份验证器APP ...

  5. Docker 入门教程(4)——docker-compse 服务编排

    Docker compose 简介 compose是用来定义和运行多个Docker容器. 比如一个简单的web项目,除了web服务之外,我们可能要需要数据库容器.注册中心容器等等.那我们需要: 定义各 ...

  6. JS获取格式为YYYY-MM-DD的当前日期

    JS获取格式为YYYY-MM-DD的当前日期 var date = new Date();  var mon = date.getMonth() + 1; var day = date.getDate ...

  7. 初识Http

     HTTP是一个用在计算机世界里的协议,它确立了一种计算机之间交流通信的规范,以及相关的各种控制 和错误处理方式.  HTTP专门用来在两点之间传输数据,不能用于广播.寻址或路由. HTTP传输的是文 ...

  8. 《Python金融大数据分析》高清PDF版|百度网盘免费下载|Python数据分析

    <Python金融大数据分析>高清PDF版|百度网盘免费下载|Python数据分析 提取码:mfku 内容简介 唯一一本详细讲解使用Python分析处理金融大数据的专业图书:金融应用开发领 ...

  9. 《Python编程初学者指南》高清PDF版|百度网盘免费下载|Python基础

    <Python编程初学者指南>|百度网盘免费下载| 提取码:03b1 内容简介 Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.Python可以用于很多的领域,从科学计 ...

  10. 对‘sqrt’未定义的引用

    首先, 引用数学库 #include<math.h> 引用数学库时,要在编译后加上-lm 是每一个都要加!! 如下: gcc su.c -o su.o -lm gcc -g  su.c - ...