前几天大连下了几十年不遇的大雪,虽然给上下班造成了不少麻烦,但是小朋友们却十分高兴,在小区里打雪仗,堆雪人。
小区的商店里竟然在大卖滑雪板,一时间静谧的山谷小区竟成了游乐场,给在疫情下压抑了一年多,不能出门旅游的人们免费送了一个雪乡数日游。
今天是日本人的休假日“成人の日”,所以给日本客户做技术支持的我也就在家休息里,趁此时间和大家继续聊聊关于数据库的那些事儿。
上次我们谈到了“随机I/O”的寻道时间是如何对数据块读写产生的的影响,今天我们来聊聊聪明的工程师们想了那些方法来解决或者说改善这些问题的。
先说“随机I/O”对写操作的影响的解决方法,这里的“写”专门指数据块更新(“UPDATE”和“DELETE”)时的写操作,“INSERT”当然也收到随机I/O的影响,但是涉及到的数据块查找算法和更新时不同,
我们今天不在这里赘述了。 当然如果有同学想仔细了解一下“INSERT”是的数据块查找动作,可以留言,我们在以后找机会详述。
因为更新(“UPDATE”和“DELETE”)操作是根据“Where”条件对特定的数据块进行写操作,所以对这些数据块更新时将不可避免发生“随机I/O”,那么如何解决这个看似没法解决的问题呢。
大家一起来思考5分钟。
对了,就是先把这些更新数据块的操作写到一个文件 -- Redo Log中。
那么为什么上面的方法就可以解决“随机I/O”问题呢,因为这是一个把“随机I/O”转化为“连续I/O”的方法。
下面我们先来说一下什么是“连续I/O”,在上一篇文章里我们知道了HDD硬盘的寻道方法,所以如果写操作不是针对特定的数据块,而是直接寻道到Redo Log文件的最后,然后连续写多个扇区的话,
那么“随机I/O”中浪费掉的寻道时间将会大大缩小。这就是传统的HDD硬盘的“连续I/O”。
那么问题来了,数据块的变化被写到了Redo Log中,似乎并没有达到我们的目的,把变化更新到数据块中去。
不错,我们只是进行了下面的处理,就告诉APPLICATION数据库更新完毕了。
1. 把更新对象数据块读到内存。
2. 把更新写到内存中的数据块。
3. 当满足一定条件货或有Commit请求时,把更新以“**连续I/O**”写到Redo Log。
4. 告诉APPLICATION说数据库更新完毕了。
那什么时候写数据块呀?呵呵,这个可以用后台Process偷偷的做就可以呀。
现在把前面说的简单的总结一下:为了改善HDD硬盘的“随机I/O”对更新(“UPDATE”和“DELETE”)处理的影响,所以引进了“Redo Log”,用“Redo Log”文件的“连续I/O”代替“随机I/O”。
是不是感觉听起来怪怪的,以前只听说“Redo Log”是备份回复数据用的,没听说过还有这个作用呀?
对的,这是 “Redo Log”的另外一个重要的作用,但是用“连续I/O”改善“随机I/O”的因素也确实是一个重要的考虑。
这也是为什么以ORACLE为主的RDBMS关系数据库都涉及了REDO LOG,并且把写LOG文件放在写数据文件之前。
说完了“随机I/O”对写操作的影响的解决方法,下面我们来聊聊它对读操作(SELECT)的影响的解决方法。
因为数据被存在数据库里(“INSERT”)以及后期的更新(“UPDATE”和“DELETE”),体现的都是数据的原始价值,既数据被安全的保存了起来。
而对数据的查询(“SELECT”)则体现了数据的附加价值,既数据可以根据各种各样的需求被检索出来,为了价值更高的行为或决策提供依据。
所以任何一款数据库对SELECT的优化的是重中之重,具体方法也是八仙过海,各显神通。
基于以上的原因和我自身知识的不足,今天就不能都一一说明了,我们只是从如何减少“随机I/O”的观点来简单的说明一下。
以ORACLE为主的关系数据库用以下两个方法减少“随机I/O”:
1. 利用内存缓存(Buffer Cache)来存放被读进来数据块,并且共享给所有PROCESS。这样就可以尽可能的降低同一数据块的反复读入。
把这个思想发展到极致就是例如HANA之类的内存数据库。
当然还有类似Redis之类的中间件数据库,他可以帮助Mysql之类的内存缓存算法不完善的数据库提供额外的内存缓存功能。
2. 把同一列,而不是同一行的数据存在一个数据块里,以方便SUM,AVG之类的集计处理。
利用这个思路做成的数据库就是著名的 数据仓库(Data Warehouse)。
后来ORACLE在12c以上的版本里提出了“In Memory”概念,其实就是在传统的“行存储”数据库的内存里,单独开辟出一块内存区域,
在这个区域里数据以“列存储”的方式提供给SELECT访问。这个理念也被后来的TiDB以“TiFlash”方式采用了。
今天就写到这里吧。
下篇文章聊聊多个PROCESS同时更新一条数据记录时处理方式。
2021/01/11 @ Dalian
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。