经过上图能够直接的看出, 在MyISAM对B+树的运用中明显的特色以下:node
MyISAM引擎 索引文件的查看: mysql
在 /var/lib/mysql目录中算法
.myd 即 my data , 数据库中表的数据文件sql
.myi 即 my index , 数据库中 索引文件数据库
.log 即 mysql的日志文件centos
InnoDB引擎 索引文件的查看: 性能
一样在 /var/lib/mysql 目录下面操作系统
InnoDB的实现方式业内也称其为聚簇索引, 什么是聚簇索引呢? 就是相邻的行的简直被存储到一块儿, 对比上面的两幅图片就会发现, 在InnDB中, B+树的叶子节点中存储的是数据行中的一行行记录, 缺点: 由于索引文件被存放在硬盘上, 因此很占硬盘的空间.net
通常咱们会在每个表中添加一列 取名 id, 设置它为primary key , 即将他设置成主键, 若是使用的存储引擎也是InnoDB的话, 底层就会创建起主键索引, 也是聚簇索引, 而且会自动按照id的大小为咱们排好序,(由于它的一个有序的树)日志
局部性原理是指CPU访问存储器时,不管是存取指令仍是存取数据,所访问的存储单元都趋于汇集在一个较小的连续区域中。 更进一步说, 当咱们经过程序向操做系统发送指令让它读取咱们指定的数据时, 操做系统会一次性读取一页(centos 每页4kb大小,InnoDB存储引擎中每一页16kb)的数据, 它遵循局部性理论, 猜想当用户须要使用某个数据时, 用户极可能会使用这个数据周围的数据,故而进行一次
什么是页呢? 简单说,就是一条条数据被的存储在磁盘上, 使用数据时须要先将数据从磁盘上读取到内存中, 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 | 文件尾部 , 用来校验页是否完整 |
每一页中存储的行数据越多. 总体的性能就会越强
compact的行格式以下图所示
能够看到在行格式中在存储真正的数据的前面会存储一些其余信息, 这些信息是为了描述这条记录而不得不添加的一些信息, 这些额外的信息就是上图中的前三行
在mysql中char是固定长度的类型, 同时mysql还支持诸如像 varchar这样可变长度的类型, 不止varchar , 想 varbinary text blob这样的变长数据类型, 由于 变长的数据类型的列存储的数据的长度是不固定的, 因此说咱们在存储真正的数据时, 也得将这些数据到底占用了多大的长度也给保存起来
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 | 表示下一条记录的相对位置 |
在mysql中每一行, 能存储的最大的字节数是65535个字节数, 此时咱们使用下面的sql执行时就会出现行溢出现象
CREATE TABLE test ( c VARCHAR(65535) ) CHARSET=ascii ROW_FORMAT=Compact;
给varchar申请最大65535 , 再加上compact行格式中还有前面三个非数据列占用内存,因此一准溢出, 若是不想溢出, 能够适当的将 65535 - 3
前面说了, InnoDB中数据的读取按照页为单位, 每一页的大小是 16kb, 换算成字节就是16384个字节, 可是每行最多存储 65535个字节啊, 也就是说一行数据可能须要好几个页来存储
怎么办呢?
通常咱们都是将表中的id列设置为主键, 这就会造成主键索引, 因而咱们须要注意了:
主键的占用的空间越小,总体的检索效率就会越高
为何这么说呢? 这就能够结合页的概念来解析, 在B+树这种数据结果中, 叶子节点中用来存储数据, 存储数据的格式相似Key-value key就是索引值, value就是数据内容, 若是索引占用的空间太大的话, 单页16kb能存储的索引就越小, 这就致使数据被分散在更多的页上, 导致查询的效率下降
为某一列创建索引
给text表中的title列建立索引, 索引名字 my_index alter table text add index my_index (title);
虽然创建索引能提高查询的效率, 根据前人的经验看, 这并非必定的, 创建索引自己会直接消耗内存空间, 同时索, 插入,删除, 这种写操做就会打破B+树的平衡面临索引的重建, 通常出现以下两种状况时,是不推荐创建索引的
所谓选择性,其实就是说不重复出现的索引值(基数,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
使用联合索引进行查询时必定要遵循左前缀原则, 什么是左前缀原则呢? 就是说想让索引生效的话,必定要添加上第一个索引, 只使用第二个索引进行查询的话会致使索引失效
好比上面建立的联合索引, 假如咱们的查询条件是 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;