Mysql作为关系型数据库的一种,它的开源免费特性以及支持百万级存储性能,备受互联网公司的喜爱,我个人在做研究生的项目以及去互联网公司实习的期间,大部分接触的也都是基于Mysql作为底层数据的存储,CRUD用的比较多,稍微复杂一点就是多条查询,各种内外连接以及group by操作,对于Mysql数据库原理特性以及底层机制的研究不够深入,因此,本篇文章主要是研究Mysql原理特性。(文章中截图来自于网上的好多博客)
(1)Mysql常用的引擎
1. InnoDB
InnoDB 的存储文件有两个,后缀名分别是 .frm 和 .idb,其中 .frm 是表的定义文件,而 idb 是数据文件。
InnoDB 中存在表锁和行锁,不过行锁是在命中索引的情况下才会起作用。
InnoDB 支持事务,且支持四种隔离级别(读未提交、读已提交、可重复读、串行化),默认的为可重复读;而在 Oracle 数据库中,只支持串行化级别和读已提交这两种级别,其中默认的为读已提交级别。
InnoDB 中的 B+Tree
InnoDB 是以 ID 为索引的数据存储。采用 InnoDB 引擎的数据存储文件有两个,一个定义文件,一个是数据文件。
InnoDB 通过 B+Tree 结构对 ID 建索引,然后在叶子节点中存储记录。
若建索引的字段不是主键 ID,则对该字段建索引,然后在叶子节点中存储的是该记录的主键,然后通过主键索引找到对应的记录。
2. Myisam
Myisam 的存储文件有三个,后缀名分别是 .frm、.MYD、MYI,其中 .frm 是表的定义文件,.MYD 是数据文件,.MYI 是索引文件。Myisam 只支持表锁,且不支持事务。Myisam 由于有单独的索引文件,在读取数据方面的性能很高 。
Myisam 中的 B+Tree:
Myisam 引擎也是采用的 B+Tree 结构来作为索引结构。由于 Myisam 中的索引和数据分别存放在不同的文件,所以在索引树中的叶子节点中存的数据是该索引对应的数据记录的地址,由于数据与索引不在一起,所以 Myisam 是非聚簇索引。
InnoDB 和 Myisam 都是用 B+Tree 来存储数据的,目前常用的Mysql引擎是InnoDB,原因在于它支持行级锁、支持事务。
(2)MySQL 的数据、索引存储结构
说到Mysql的数据、索引存储结构,就得先介绍Mysql数据库数据的存储方式以及Mysql的索引了。
1、Mysql数据库数据存储的原理
数据库数据都是以磁盘文件的方式存储到系统当中的,存储方式如下:信息存储在硬盘里,硬盘是由很多的盘片组成,通过盘片表面的磁性物质来存储数据。
A、访盘请求完成过程
硬盘在逻辑上被划分为磁道、柱面以及扇区。
1)确定磁盘地址(柱面号,磁头号,扇区号),内存地址(源 / 目):当需要从磁盘读取数据的时候,系统会将数据的逻辑地址传递个磁盘,磁盘的控制电路按照寻址逻辑将逻辑地址翻译成物理地址,即确定要读的数据在哪个磁道,哪个扇区。
2)为了读取这个扇区的数据,需要将磁头放到这个扇区上方,为了实现这一点:
A. 首先必须找到柱面,即磁头需要移动对准相应磁道,这个过程叫做寻道,所耗费时间叫做寻道时间。
B. 然后目标扇区旋转到磁头下,即磁盘旋转将目标扇区旋转到磁头下,这个过程耗费的时间叫做旋转时间。
3)即一次访盘请求(读 / 写)完成过程由三个动作组成:
A. 寻道(时间):磁头移动定位到指定磁道。
B. 旋转延迟(时间):等待指定扇区从磁头下旋转经过。
C. 数据传输(时间):数据在磁盘与内存之间的实际传输。
B、磁盘的读写原理
系统将文件存储到磁盘上时,按柱面、磁头、扇区的方式进行,即最先是第 1 磁道的第一磁头下的所有扇区,然后是同一柱面的下一个磁头……
一个柱面存储满后就推进到下一个柱面,直到把文件内容全部写入磁盘。系统也以相同的顺序读出数据,读出数据时通过告诉磁盘控制器要读出扇区所在柱面号、磁头号和扇区号(物理地址的三个组成部分)进行。
C、减少 I/O 的预读原理
磁盘读取文件,效率太低,因此需要减少访问磁盘IO的频率。
磁盘预读原理:
磁盘往往不是严格地按需读取,而是每次都会预读,即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存。
这样做的理论依据是计算机科学中著名的局部性原理:
-
当一个数据被用到时,其附近的数据一般来说也会被马上使用。
-
程序运行期间所需要的数据通常比较集中。
-
由于磁盘顺序读取的效率很高(不需要寻道时间,只需要很少的旋转时间),因此对于具有局部性的程序来说,预读可以提高 I/O 效率。
预读的长度一般为页(Page)的整数倍。页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储分割为连续的大小相等的块。
每个存储块称为一页(在许多操作系统中,页的大小通常为 4k),主存和磁盘以页为单位交换数据,当程序要读取的数据不在主存中时,会触发一个缺页异常。
此时系统会向磁盘发出读盘信息,磁盘会找到数据的起始位置并向后连续读取一页或几页的数据载入内存中,然后异常返回,程序继续运行。
2、Mysql索引
索引是一种用来实现 MySQL 高效获取数据的数据结构。我们通常所说的在某个字段上建索引,意思就是让 MySQL 对该字段以索引这种数据结构来存储,然后查找的时候就有对应的查找算法。
建立索引的原因:
为了查找的优化,特别是当数据很庞大的时候,采用特殊的查找算法,可以实现数据的高效快速查询。
特殊查找算法:
Mysql数据库索引采用的数据结构是B tree和B+ tree。
为什么要采用B tree和B+ tree?
一般的查找算法有顺序查找、折半查找、快速查找等,但是每种查找算法都只能应用于特定的数据结构之上,例如顺序查找依赖于顺序结构,折半查找通过二叉查找树或红黑树实现二分搜索。这样的索引数据结构还是会对数据库的数据结构有要求,而且对磁盘IO的操作依旧很频繁。因此采用了B树和B+ 树.
注:二分查找算法的时间复杂度计算:
比如:总共有n个元素,每次查找的区间大小就是n,n/2,n/4,…,n/2^k(接下来操作元素的剩余个数),其中k就是循环的次数。 由于n/2^k取整后>=1,即令n/2^k=1, 可得k=log2n,(是以2为底,n的对数),所以时间复杂度可以表示O()=O(logn)
红黑树: