当二进制看到世界:MySQL 到底是如何存数据的 想象一下,你手里有一堆红砖,要把它们码成一堵墙。在 MySQL 的世界里,数据就是那些红砖,而磁盘是地基。你根本不需求搬着墙去砌地,你得先学会如何把一块砖变成“砖块”的代码,再把它扔进地基的缝隙里。
这就是 MySQL 的底层逻辑,它不玩虚的,直接面对物理世界。 数据根本不该停留在内存里,内存是脆弱的,断电就完了。数据库的核心任务是把逻辑好的东西,变成物理好的东西。你在大屏幕上查一行数据,那是逻辑层;当找到那行数据时, MySQL 得想个方式,把那行数据从内存里捞出来,搬运到硬盘的某个具体字节位置。
要是不如此做,那行数据下一秒就会消亡。
这个过程一般形成在磁盘 IO 形成的瞬间,中间会形成一次或多次内存到磁盘的拷贝。 这个搬运动作叫拷贝(Copy-on-Write),听起来像是一种高级操作,实际上它就是复制内存页。当数据被搬运到磁盘时,整个页就挂了,原来的内存页就不能再被引用了。
这时候,要是还有哪位想查这个数据,还得重新把它从硬盘搬回内存,然后再交给操作系统去处理。
这就好比你想翻书,你先把书页翻转到手边,这时候书页就变空了。
要是赶明儿还有哪位想看,就得重新翻。
这种机制叫 Copy-on-Write,好办点说,就是换个地方存,原来的地方先挂了。 知道了搬运的原理,再说说如何存。MySQL 的存结构被封装在文件里,这玩意儿叫 InnoDB 引擎。InnoDB 在文件系统上开一个文件,这个文件里存着所有的元数据,包含记录头的信息、索引表、B-Trees 这些结构。元数据是管理元数据的元数据,它告诉操作系统这块硬盘里存的是啥、多大、在哪。出于 InnoDB 是透明数据块技术的产物,它专门处理数据块,故此它自己就不形成数据块,只存数据块的信息。 数据块如何存呢?MySQL 用的是 MyISAM、MyISAM 和 InnoDB 三种存引擎。
这里主要讲 InnoDB,它用的是 MyISAM 的存格式。MyISAM 有个特征,就是它自带索引。
这意味着你不需求专门建一个索引表,数据就在文件里,索引就在文件里。并且 MyISAM 的数据比 InnoDB 大得多,出于 InnoDB 目前用的是 MyISAM 的存格式。MyISAM 在文件结构上挺粗糙,不像 InnoDB 那么精致,它的索引是单例的,一个索引只能存有于一个文件里。但 MyISAM 的数据压缩率和 InnoDB 不一样,InnoDB 的压缩率更高,出于它更智能。 InnoDB 的索引设计也挺讲究。它用的是 B-Tree 算法,这是一种平衡树。你在树里拉下来,就是那个索引。B-Tree 有个妙处,数据量大时,你能够建立多个索引,这样查询就快。并且 B-Tree 还有个特性,就是互斥性。
要是两个索引要访问同一个数据,它们得互斥,一个死锁另一个。
这个特性在 InnoDB 里用了挺久,目前还在用。 再来看看 B-Tree 是如何排数据的。你从根节点启动,根据键值的大小往下走,就像走迷宫,左边的路就是小于,右边的路就是大于。每走一步,数据就在内存里变了,出于数据被移到了新的位置。
要是你直接去物理磁盘查数据,那得先把数据从内存搬回去再查,这就挺费事。
故此,InnoDB 的索引都是存放在内存里的。你查数据时,先把索引读入内存,然后依次走一层一层,直到找到你要的数据。
这个过程叫遍历。 遍历的时候,你不需求把数据全体读入内存,只需求读那些指针对应的节点里的值。出于 B-Tree 的节点挺小,故此读入内存挺快。
要是节点里是结构体,那就要读入整个节点,这时候慢了。
要是节点是数值,那更快。InnoDB 的节点设计得挺小,主要是数值,故此比 MyISAM 快大量。 索引还能用来优化查询。
比如有个表里有 100 万行数据,你时常查 `id=1001` 和 `id=1002`。你用一般/平平查询,MySQL 可能得扫描 100 万行数据。但要是你用索引 `id=1001`,MySQL 就只需求扫描 `id` 列等于 1001 的那一行,瞬间找到。
这就是索引的功能,它让查询变得极快。 可是,索引不是万能的。
要是数据量特别大,索引维护成本挺高。
比如你时常查 `name="张三"`,MySQL 就得去全表扫描,这时候索引就没用了。
还有,索引能加速的查询,大局部是等值查询、范围查询、逻辑连接查询等。非等值查询、多列连接查询、子查询,这些 MySQL 得靠逻辑层去判断,索引帮不上忙,只能靠统计信息。统计信息是 MySQL 的助手,它告诉你哪些数据多,哪些数据少,啥时候查哪个索引更快。
要是统计信息不准,MySQL 就得瞎猜,查慢。 MySQL 的底层原理还有大量你没想到的地方。
比方说,它如何保证数据的一致性?它用事务来保证,事务要么全成功,要么全黄了。
要是中间黄了了,数据就回滚,保证一致性。它还如何防止死锁?它用锁机制,比如间隙锁,锁住一个间隙里的所有行。
要是两个事务互相锁住了,就会死锁,MySQL 就得触发回滚或重新加锁。 还有,MySQL 如何优化查询?它靠索引统计信息,用它来判断,啥时候用哪儿的索引更快。
要是别的查询还没查完,这个查询就查不到。MySQL 会在后台按需更新统计信息,让你查询时用的统计信息挺准。 最终,MySQL 如何保证数据的保险?它靠加密,比如存过程加密,数据在传输时加密。它靠备份,定期备份数据,保证数据不丢也不乱。 总结来说,MySQL 底层就是靠磁盘 IO 和内存拷贝来实现数据的物理存和复制。它用 B-Tree 索引来加速查询,用统计信息来优化选择,用事务来保证数据一致。别看看起来复杂,但它确实挺好办,就是直接把二进制数据搬到硬盘上,再拿回来用。
这就是 MySQL 的底层原理,也是它为啥能跑得那么快的缘由。