MyISAM引擎的B+Tree的索引

通过上图可以直接的看出, 在MyISAM对B+树的运用中明显的特点如下:

  • 所有的非叶子节点中存储的全部是索引信息
  • 在叶子节点中存储的 value值其实是 数据库中某行数据的index

**MyISAM引擎 索引文件的查看: **

在 /var/lib/mysql目录中

.myd 即 my data , 数据库中表的数据文件

.myi 即 my index , 数据库中 索引文件

.log 即 mysql的日志文件

**InnoDB引擎 索引文件的查看: **

同样在 /var/lib/mysql 目录下面

InnoDB引擎的B+Tree的索引

InnoDB的实现方式业内也称其为聚簇索引, 什么是聚簇索引呢? 就是相邻的行的键值被存储到一起, 对比上面的两幅图片就会发现, 在InnDB中, B+树的叶子节点中存储的是数据行中的一行行记录, 缺点: 因为索引文件被存放在硬盘上, 所以很占硬盘的空间

一般我们会在每一个表中添加一列 取名 id, 设置它为primary key , 即将他设置成主键, 如果使用的存储引擎也是InnoDB的话, 底层就会建立起主键索引, 也是聚簇索引, 并且会自动按照id的大小为我们排好序,(因为它的一个有序的树)

点击查看 参考博文1

局部性原理

局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。 更进一步说, 当我们通过程序向操作系统发送指令让它读取我们指定的数据时, 操作系统会一次性读取一页(centos 每页4kb大小,InnoDB存储引擎中每一页16kb)的数据, 它遵循局部性理论, 猜测当用户需要使用某个数据时, 用户很可能会使用这个数据周围的数据,故而进行一次读取

InnoDB的页格式

什么是页呢? 简单说,就是一条条数据被的存储在磁盘上, 使用数据时需要先将数据从磁盘上读取到内存中, InnoDB每次读出数据时同样会遵循 局部性原理, 而不是一条条读取, 于是InnoDB将数据划分成一个一个的页, 以页作为和磁盘之间交互的基本单位

通过如下sql, 可以看到,InnoDB中每一页的大小是16kb

show global status like 'Innodb_page_size';

名称 简述
File Header 文件头部, 存储页的一些通用信息
Page Header 页面头部, 存储数据页专有的信息
Infinum + supremum 最大记录和最小记录, 这是两个虚拟的行记录
User Records 用户记录, 用来实际存储行记录中的内容
Free Space 空闲空间, 页中尚位使用的空间
Page Directory 页面目录, 存储页中某些记录的位置
File Tailer 文件尾部 , 用来校验页是否完整

InnoDB的行格式 compact

每一页中存储的行数据越多. 整体的性能就会越强

compact的行格式如下图所示

可以看到在行格式中在存储真正的数据的前面会存储一些其他信息, 这些信息是为了描述这条记录而不得不添加的一些信息, 这些额外的信息就是上图中的前三行

  • 变长字段的长度列表

在mysql中char是固定长度的类型, 同时mysql还支持诸如像 varchar这样可变长度的类型, 不止varchar , 想 varbinary text blob这样的变长数据类型, 因为 变长的数据类型的列存储的数据的长度是不固定的, 所以说我们在存储真正的数据时, 也得将这些数据到底占用了多大的长度也给保存起来

  • NULL标志位

compact行格式会将值可以为NULL的列统一标记在 NULL标志位中, 如果数据表中所有的字段都被标记上not null , 那么就没有NULL值列表

  • 记录头信息

记录头信息, 顾名思义就是用来描述记录头中的信息, 记录头信息由固定的5个字节组成, 一共40位, 不同位代表的意思也不同, 如下表

名称 单位 bit 简介
预留位1 1 未使用
预留位2 1 未使用
delete_mark 1 标记改行记录是否被删除了
min_rec_mark 1 标记在 B+树中每层的非叶子节点中最小的node
n_owned 4 表示当前记录拥有的记录数
heap_no 13 表示当前记录在堆中的位置
record_type 3 表示当前记录的类型 , 0表示普通记录, 1表示B+树中非叶子节点记录, 2表示最小记录 ,3表示最大记录
next_record 16 表示下一条记录的相对位置

点击查看 参考博文2

行溢出

在mysql中每一行, 能存储的最大的字节数是65535个字节数, 此时我们使用下面的sql执行时就会出现行溢出现象

CREATE TABLE test ( c VARCHAR(65535) ) CHARSET=ascii ROW_FORMAT=Compact;

给varchar申请最大65535 , 再加上compact行格式中还有前面三个非数据列占用内存,所以一准溢出, 如果不想溢出, 可以适当的将 65535 - 3

页溢出

前面说了, InnoDB中数据的读取按照页为单位, 每一页的大小是 16kb, 换算成字节就是16384个字节, 但是每行最多存储 65535个字节啊, 也就是说一行数据可能需要好几个页来存储

怎么办呢?

  • compact行格式会在存储真实数据的列中多存储一部分数据, 这部分数据中存储的就是下一页的地址
  • dynamic行格式 中直接存储数据所在的地址, 换句话说就是数据都被存储在了其他页上
  • compressed行格式会使用压缩算法对行格式进行压缩处理

**一般我们都是将表中的id列设置为主键, 这就会形成主键索引, 于是我们需要注意了: **

主键的占用的空间越小,整体的检索效率就会越高

为什么这么说呢? 这就可以结合页的概念来解析, 在B+树这种数据结果中, 叶子节点中用来存储数据, 存储数据的格式类似Key-value key就是索引值, value就是数据内容, 如果索引占用的空间太大的话, 单页16kb能存储的索引就越小, 这就导致数据被分散在更多的页上, 致使查询的效率降低

建立索引的技巧

为某一列建立索引

给text表中的title列创建索引, 索引名字 my_index
alter table text add index my_index (title);

虽然建立索引能提升查询的效率, 根据前人的经验看, 这并不是一定的, 建立索引本身会直接消耗内存空间, 同时索, 插入,删除, 这种写操作就会打破B+树的平衡面临索引的重建, 一般出现如下两种情况时,是不推荐建立索引的

  1. 表中的数据本身就很少
  2. 我们计算一下索引的选择性很低

兼顾 - 索引的选择性与前缀索引

所谓选择性,其实就是说不重复出现的索引值(基数,Cardinality) 与 表中的记录数的比值

即: 选择性= 基数 / 记录数

选择性的取值范围在(0,1]之间, 选择性越接近1 , 说明建立索引的必要性就越强, 比如对sex列进行建立索引,这里面非男即女, 如果对它建立索引的话, 其实是没意义的, 还不如直接进行全表扫描来的快

如何使用sql计算选择性呢? 严格遵循上面的公式

SELECT count(DISTINCT(title))/count(*) AS Selectivity FROM employees.titles;
count(基数/记录数)
DISTINCT(title) / /count(*)

更详细的例子看下面的连接

参考博文

索引失效问题

注意事项

  • 索引无法存储null值

  • 如果条件中有or, 即使条件中存在索引也不会使用索引,如果既想使用or,又想使用索引, 就给所有or条件控制的列加上索引

  • 使用like查询时, 如果以%开头,肯定是进行全表扫描

  • 使用like查询时, 如果%在条件后面

    • 对于主键索引, 索引失效
    • 对于普通索引, 索引不失效
  • 如果列的类型是字符串类型, 那么一定要在条件中将数据用引号引起来,不然也会是索引失效

  • 如果mysql认为全表扫描比用索引块, 同样不会使用索引

联合索引

什么是联合索引

联合索引, 也叫复合索引,说白了就是多个字段一起组合成一个索引

像下面这样使用 id + title 组合在一起构成一个联合索引

CREATE TABLE `text` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`content` text NOT NULL,
PRIMARY KEY (`id`,`title`)
) ENGINE=InnoDB AUTO_INCREMENT=3691 DEFAULT CHARSET=utf8
  • 如果我们像上图那样创建了索引,我们只要保证我们的 id+title 两者结合起来全局唯一就ok
  • 建立联合索引同样是需要进行排序的,排序的规则就是按照联合索引所有列组成的字符串的之间的先后顺序进行排序, 如a比b优先

左前缀原则

使用联合索引进行查询时一定要遵循左前缀原则, 什么是左前缀原则呢? 就是说想让索引生效的话,一定要添加上第一个索引, 只使用第二个索引进行查询的话会导致索引失效

比如上面创建的联合索引, 假如我们的查询条件是 where id = '1' 或者 where id = '1' and title = '唐诗宋词' 索引都会不失效

但是如果我们不使用第一个索引id, 像这样 where title = '唐诗' , 结果就是导致索引失效

联合索引的分组&排序

还是使用这个例子:

CREATE TABLE `text` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`content` text NOT NULL,
PRIMARY KEY (`id`,`title`)
) ENGINE=InnoDB AUTO_INCREMENT=3691 DEFAULT CHARSET=utf8

demo1: 当我们像下面这样写sql时, 就会先按照id进行排序, 当id相同时,再按照title进行排序

select * form text order by id, title;

demo2: 当我们像下面这样写sql时, 就会先将id相同的划分为一组, 再将title相同的划分为一组

select id,title form text group by id, title;

demo3: ASC和DESC混用, 其实大家都知道底层使用B+树, 本身就是有序的, 要是不加限制的话,默认就是ASC, 反而是混着使用就使得索引失效

select * form text order by id ASC, title DESC;

如何定位慢查询

相关参数

名称 简介
slow_query_log 慢查询的开启状态
slow_query_log_file 慢查询日志存储的位置
long_query_time 查询超过多少秒才记录下来

常用sql

# 查看mysql是否开启了慢查询
show variables like 'slow_query_log';
# 将全局变量设置为ON
set global slow_query_log ='on';
# 查看慢查询日志存储的位置
show variables like 'slow_query_log_file';
# 查看规定的超过多少秒才被算作慢查询记录下来
show variables like 'long_query_time';
show variables like 'long_query%';
# 超过一秒就记录 , 每次修改这个配置都重新建立一次链接
set global long_query_time=1;

mysql 索引笔记的更多相关文章

  1. MySql索引笔记

    MySQL 索引是什么 MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度. 打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和 ...

  2. mysql 索引- 笔记

    索引 mysql最常用的索引结构是btree(O(log(n))),但是总有一些情况下我们为了更好的性能希望能使用别的类型的索引.hash就是其中一种选择,例如我们在通过用户名检索用户id的时候,他们 ...

  3. mysql 索引 笔记1

    #不同的存储引擎支持的索引类型也不一样 InnoDB 支持事务,支持行级别锁定,支持 B-tree.Full-text 等索引,不支持 Hash 索引: MyISAM 不支持事务,支持表级别锁定,支持 ...

  4. 关于Mysql索引的笔记

    MySQL索引原理 索引目的 索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql.如果没有索引,那么你可能需 ...

  5. mysql学习笔记-- 多表查询之外键、表连接、子查询、索引

    本章主要内容: 一.外键 二.表连接 三.子查询 四.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复 ...

  6. SQL学习笔记五之MySQL索引原理与慢查询优化

    阅读目录 一 介绍 二 索引的原理 三 索引的数据结构 四 聚集索引与辅助索引 五 MySQL索引管理 六 测试索引 七 正确使用索引 八 联合索引与覆盖索引 九 查询优化神器-explain 十 慢 ...

  7. SQL学习笔记之MySQL索引知识点

    0x00 概述 之前写过一篇Mysql B+树学习,简单的介绍了B+数以及MySql使用B+树的原因, 有了这些基础知识点,对MySql索引的类型以及索引使用的一些技巧,就比较容易理解了. 0x01 ...

  8. Mysql 索引复习笔记

    之前学习索引后由于一直没怎么用,所以也只是粗略看了一下,最近发现索引的用处很大,并且也很多知识点,在此做复习记录. 什么是索引? 百度百科是这样描述的: 索引是为来加速对表中数据行中的检索而创建的一种 ...

  9. Mysql索引学习笔记

    1.btree索引与hash索引 下列范围查询适用于 btree索引和hash索引: SELECT * FROM t1 WHERE key_col = 1 OR key_col IN (15,18,2 ...

随机推荐

  1. 一张图看懂Rxjava的原理

    前言 Rxjava是NetFlix出品的Java框架, 官方描述为 a library for composing asynchronous and event-based programs usin ...

  2. Typora忘记保存的文件怎么找回

    打开Typora,选择文件--偏好设置,在通用设置下点击恢复未保存的草稿,就可以找到你所有未保存的文件.

  3. Linux Centos7 基于Docker 搭建 Nexus私服搭建

    创建Blob Stores[本地文件存储目录,统一管理] 1.设置名称和工作路径: ps[注意事项]: 1.storage name:自定义名称 2.storage path:存储路径,默认[/nex ...

  4. ESP8266开发之旅 应用篇① 局域网应用 ——炫酷RGB彩灯

    1.前言     这一篇,博主将教大家怎么去实现一个WiFi RGB彩灯.     先来一个博主已经实现功能的图片,如下:     当然,博主也拍了运行视频,请点击 传输门. 1.1 知识储备     ...

  5. Java虚拟机类加载器及双亲委派机制

    所谓的类加载器(Class Loader)就是加载Java类到Java虚拟机中的,前面<面试官,不要再问我"Java虚拟机类加载机制"了>中已经介绍了具体加载class ...

  6. react中使用redux简易案例讲解

    为什么我想要使用redux? 前段时间初步上手了react,最近在使用react的过程中发现对于组件之间通信的需求比较迫切,尤其是在axios异步请求后端数据的时候,这样的需求是特别强烈的!举个例子: ...

  7. day10作业(函数实现注册''')

    在猜年龄的基础上编写登录.注册方法,并且把猜年龄游戏分函数处理,如 登录函数 注册函数 猜年龄函数 选择奖品函数 '''在猜年龄的基础上编写登录.注册方法,并且把猜年龄游戏分函数处理,如 2. 登录函 ...

  8. redis入门(二)

    目录 redis入门(二) 前言 持久化 RDB AOF 持久化文件加载 高可用 哨兵 流程 安装部署 配置技巧 集群 原理 集群搭建 参考文档 redis入门(二) 前言 在redis入门(一)简单 ...

  9. ARToolKit-unity

    ARToolKit为开源的AR库,相对于高通和easyAr有几点特点: 1)开源 2)识别项目可以动态添加(详细在后) 3)识别文件可以本地生成 4)目前只能识别图片(目前为.jpg格式) 下边开始详 ...

  10. 快速学习ggplot2

    R语言里面一个比较重要的绘图包——ggplot2,是由Hadley Wickham于2005年创建,于2012年四月进行了重大更新,作者目前的工作是重写代码,简化语法,方便用户开发和使用.ggplot ...