本篇博客为数据库框架Realm的调研笔记第二篇,第一篇主要是介绍Realm的使用,该篇博客则是根据Realm官网上对其数据库引擎性能优秀的介绍[1]写下自己的一些理解。

一、MVCC 多版本并发控制[2][3]
Realm使用MVCC,而不是使用锁来达到Repeated Read级别的事务隔离。这里简单介绍一下MVCC。
数据库在事务隔离级别中处理不可重复读时,一种实现方式是使用锁,在一个数据库连接中写数据时,其他数据库连接不能进行读操作,这种方式比较影响性能。另一种方式是使用MVCC,每一个数据库连接拥有一份基于时间的数据库快照,数据库的写操作并不会直接替换数据库中的数据,而是将旧数据标记为废弃,并增加新版本的数据,也就是insert+update的操作方式来存储多个版本的数据,并且该数据的变更只会影响到事务提交之后发生的读操作,在未提交事务之前发生的读操作只会读到该读操作开始的时间时的数据库快照对应的旧版本的数据,正在写的数据对其不可见。同时,如果某个版本的数据已经不存在任何对应的读事务操作,则会将版本的数据回收掉。
MVCC中的概念还包括写时拷贝技术,见下面的崩溃保护。
不同数据库引擎采用了不一样的MVCC的实现方式,比如innodb[3],realm的具体实现方式由于代码暂未开源,现在还不得而知。这里需要留待以后继续研究。
对比sqlite 通过使用锁来完成read commit级别的事务隔离,Realm的性能优势就体现出来了。

二、Sting优化
Realm中对String进行了优化,Realm使用了类Object-c里面的tagged point的概念。Realm首先会遍历数据库中的字符串,将存放在堆中的重复的字符串转变为存放在栈中的枚举(注:Realm数据库引擎采用C++实现,在C++中枚举存放在栈中),因此加快了查询的速度。

三、崩溃保护
当我们尝试进行数据库更新时,Realm就会启动写时拷贝技术[4]。我们并不直接修改数据,而是在拷贝的数据上进行修改。当我们提交修改的时候,如果此时能够安全同步到硬盘中,则会移动指针到这个新的正式版本上来。这就意味着在最坏的情况下,你只会丢失当前正在进行的修改,而不会丢失所有数据。类似git,当我们需要修改数据时,就开一个分支,在这个分支上进行修改,然后确认可以安全同步时,再将数据同步过来。

四、零拷贝
普通的ORM数据库,当我们需要访问对象中的某个属性时,ORM会将其转换为一个SQL语句,如果还未连接数据库的话则创建一个数据库连接,然后将这个 SQL 语句发送给硬盘,执行检索,从匹配检索的结果中读取所有的数据,然后将它们放到内存当中(也就是内存分配)。然而,这时候你需要对其格式进行反序列化(deserialize),因为硬盘上存储的格式不能直接在内存中使用。
但Realm则是跳过了整个拷贝过程,文件始终是内存映射的,这样无需反序列化操作。

五、真实的懒加载
SQLite等大多数数据库采用水平层级存储数据,就是按行存储,当我们从SQLite中读取数据时,会一并取出一行的数据,而Realm则是垂直层级存储,也就是按列存储,真正用到了某个数据时才会将其加载出来,避免了在磁盘中往返以及读取未使用过的属性。

六、内部加密
SQLCipher的加密方式实际上是挂接到底层引擎,并重做了很多sqlite引擎本身的工作,而Realm则是直接在引擎中进行加密。

参考文献
[1]https://realm.io/cn/news/jp-simard-realm-core-database-engine/
[2]https://en.wikipedia.org/wiki/Multiversion_concurrency_control
[3]http://blog.csdn.net/chosen0ne/article/details/18093187
[4]https://zh.wikipedia.org/wiki/%E5%AF%AB%E5%85%A5%E6%99%82%E8%A4%87%E8%A3%BD