最近大佬优化了一条SQL,讲100万条的数据查询速度从27s降低到了0.8S,因此研究了下MySQL优化的原理和方式。下面将从Mysql中索引的本质,原理等方面介绍下MySQL中的索引原理。


1、MySQL中数据的存储方式;

mysql的数据在磁盘上的存储:
A、数据块:
由多个磁盘block组成的块,存储引擎负责管理数据块。
磁盘是block块设备,数据在磁盘上的存放也是按照块存放的。
mysql读取表到内存的时候,也必然是按照一块一块的方式读取。假设 要查询的表在和其他表在都在同一个块内。加载块的时候除了读取要查询的表,其他表也一并被读取出来。
当一个块内的部分表被删除时,这是就是形成了碎片。这样会降低装载到内存的速度。
所以会生成一个块头,记录一个快内表的大小,有无空闲空间,空闲空间的位置。
B、散列文件组织:
人为将表分成多个部分,每个部分称为桶。根据行中的某个或某些字段做使用散列函数做哈希运算,运算结果属于某个范围的放在指定的桶中。多个桶组成一个表。
桶有可能溢出。所以要选定一个合适散列函数,让行平均在各个桶中。


2、什么是MySQL的索引;
引用块内容
MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。我们可以简单理解为:快速查找排好序的一种数据结构。Mysql索引主要有两种结构:B+Tree索引和Hash索引。我们平常所说的索引,如果没有特别指明,一般都是指B树结构组织的索引(B+Tree索引)。索引也是一种数据,需要占用物理空间。B+Tree索引索引的数据结构如图所示:

mysql 索引存放位置 mysql索引是如何存储的_数据


3、MySQL中索引【hash和BTree】的实现原理;


……等我研究下两种算法再确定。


4、两种索引【hash和BTree】的区别和缺点;


一、BTree


BTree索引是最常用的mysql数据库索引算法,因为它不仅可以被用在=,>,>=,<,<=和between这些比较操作符上,而且还可以用于like操作符,只要它的查询条件是一个不以通配符开头的常量,例如:


select * from user where name like ‘jack%’;


select * from user where name like ‘jac%k%’;


如果一通配符开头,或者没有使用常量,则不会使用索引,例如:


select * from user where name like ‘%jack’;


select * from user where name like simply_name;


二、Hash


Hash索引只能用于对等比较,例如=,<=>(相当于=)操作符。由于是一次定位数据,不像BTree索引需要从根节点到枝节点,最后才能访问到页节点这样多次IO访问,所以检索效率远高于BTree索引。


但为什么我们使用BTree比使用Hash多呢?主要Hash本身由于其特殊性,也带来了很多限制和弊端:


1. Hash索引仅仅能满足“=”,“IN”,“<=>”查询,不能使用范围查询。


2. 联合索引中,Hash索引不能利用部分索引键查询。


对于联合索引中的多个列,Hash是要么全部使用,要么全部不使用,并不支持BTree支持的联合索引的最优前缀,也就是联合索引的前面一个或几个索引键进行查询时,Hash索引无法被利用。


3. Hash索引无法避免数据的排序操作


由于Hash索引中存放的是经过Hash计算之后的Hash值,而且Hash值的大小关系并不一定和Hash运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算。


4. Hash索引任何时候都不能避免表扫描


Hash索引是将索引键通过Hash运算之后,将Hash运算结果的Hash值和所对应的行指针信息存放于一个Hash表中,由于不同索引键存在相同Hash值,所以即使满足某个Hash键值的数据的记录条数,也无法从Hash索引中直接完成查询,还是要通过访问表中的实际数据进行比较,并得到相应的结果。


5. Hash索引遇到大量Hash值相等的情况后性能并不一定会比BTree高


对于选择性比较低的索引键,如果创建Hash索引,那么将会存在大量记录指针信息存于同一个Hash值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据访问,而造成整体性能底下。