iOS面试-数据库比较:SQLite vs. Core Data vs. Realm(未完待续)

SQLite

SQLite是使用最多的数据库引擎,并且是开源的。它实现了无配置,无服务要求的事务数据库引擎。SQLite可以在Mac OS-X, iOS, Android, Linux, 和 Windows上使用,可以被存储在跨平台磁盘文件的完善的数据库

SQLite的优点:

  • 独立于服务器
  • 零配置
  • 多进程和线程下安全访问。
  • 在表中使用含有特殊数据类型的一列或多列存储数据。

Core Data (推荐第三方:MagicalRecord)

Core Data 是App开发者可以使用的第二大主要的IOS存储技术。你需要根据数据类型和数据量进行管理和存储,SQLite和Core Data都有它们各自的优缺点。Core Data 更加关注于对象而不是传统的表数据库方法。使用Core Data,你可以存储一个Objective-C类的对象,(Core Data本身就是基于sqlite的封装,所以它的底层仍然是使用sqlite进行存储数据的)

尽管它们从本质上不相同,但是CoreData:

  • 比SQLite使用更多的内存、更多的存储空间。
  • 比SQLite在取数据方面更快,不需要书写大量的sql语句。
  • CoreData 的数据模型升级兼容性较差,如果模型不对,会导致程序连起都起不来。虽然提供了模型升级代码,但是在客户端的管理模型版本管理也会相对复杂
  • CoreData的好处是集成化数据动态加载icloud,包括上层的数据显示,都不需要重新进行数据装配,可以直接使用
  • CoreData,建立的表没有主键,添加时都要自己处理。它不是关系型数据库,处理多对多的关系时比较麻烦。
  • CoreData的一个比较大的痛点是多人合作开发的时候,管理CoreData的模型需要很小心,尤其是合并的时候,他的data model是XML格式的,手动resolve比较烦
  • CoreData还有其他sql所不具备的优点,比如对undo的支持多个context实现sketchbook类似的功能,为ManagedObject优化的row cash等。
  • CoreData是支持多线程,但需要thread confinement的方式实现,使用了多线程之后可以最大化的防止阻塞主线程
  • CoreData自定义升级麻烦,并且效率非常低下,升级的版本变动很难跟踪,有着各种限制(抛弃它主要原因),有些限制直接导致了没法继续开发下去

iOS 8之前,Core Data没有批处理,批量插入,删除,更新效率要比sqlite低很多(这也正是很多程序员因为Core Data批量更新数据效率之低而不得不放弃使用它的原因)。 iOS8之后的Core Data 更新,正好的解决了这个痛点: Batch Updates. Batch Updates在处理大量数据时速度明显提升.Batch Updates可用于批量快速更新数据,Asynchronous Fetching可用于异步抓取海量数据,并可以通过NSProgress实现进度跟踪和取消。


Batch Updates


在CoreData中想要更新大量数据,我们往往要将大量修改后的NSManagedObject加载到NSManagedObjectContext中并保存,这会占用大量内存,试想想在iPhone这样的内存有限的移动设备上将是个灾难,数据有可能丢失。你可能会采取批处理的方式,即一小批一小批的更新NSManagedObject并保存到NSManagedObjectContext中,但这样会花费很多时间,用户体验较差。

为了解决这个问题,苹果在NSManagedObjectContext加入了一个新的方法:executeRequest:error:,它接受一个NSPersistentStoreRequest类型的参数,返回类型为NSPersistentStoreResult

关于NSPersistentStoreRequest有些人可能比较熟悉,它是NSFetchRequest、NSSaveChangesRequest、NSBatchUpdateRequestNSAsynchronousFetchRequest的基类。后两个类是这次iOS8新加的

NSPersistentStoreResult是一个新加入的类,它也是一个基类,而且是抽象类,这个类作为executeRequest:error:返回内容的父类,相当于一个接口,它目前有两个子类:NSPersistentStoreAsynchronousResultNSBatchUpdateResult`。

NSBatchUpdateResult对应着前面的NSBatchUpdateRequestNSBatchUpdateRequest,它有点像NSFetchRequest:它允许你指定一个想要更新数据的实体;也可以指定一个affectedStores,它存储了一个接受更新请求的NSPersistentStore数组。(其实它是NSPersistentStoreRequest的属性);它也有一个谓词属性来做更新的条件,它跟NSFetchRequest中的谓词一样强大和灵活,类似于SQL的where语句;它允许你指定想要更新的字段,通过propertiesToUpdate属性来描述字段更新,它是一个字段,key为NSPropertyDescription或属性名字符串,value为NSExpression或常量。

NSBatchUpdateResult,它有一个result属性和resultType属性,result中的内容跟resultType有关,可能是成功或者失败,有可能是每行被更新的ID,也可能是被更新的行数。

需要注意的是,由于NSBatchUpdateRequest并不会先将数据存入内存,而是直接操作数据库,所以并不会引起NSManagedObjectContext的同步更新,所以你不仅需要获取NSBatchUpdateResult然后刷新NSManagedObjectContext对应的数据和UI界面,还需要保证更新后的数据满足数据库模型上的validation,因为NSManagedObjectContext没有感知Batch Updates,一些数据验证工作就落在了程序员的身上(你需要写一段代码验证更新后的数据是合法的,用户可不希望在跑步APP上看到自己今天跑步里程是个负数)。一旦有非法数据录入数据库,下次加载并修改NSManagedObject的时候就会导致数据验证失败。除了上面提到的这些,还要注意Batch Updates对数据库的操作是乐观锁,也就是假定很少会发生同时存取同一块数据的情况,所以你需要制定一个合理的”merge”策略来应付因同时更新数据产生的冲突。

Batch Updates的优势在于其效率,在处理上万条数据的时候,它执行的时间跟SQL语句执行时间相当。


Asynchronous Fetching


Asynchronous Fetching 的加入依然是为了解决CoreData读取海量数据所带来的问题。通过使用 Asynchronous Fetching,我们可以在抓取数据的同时不阻塞占用 NSManagedObjectContext,并可以随时取消抓取行为,随时跟踪抓取数据的进度。

设想我们平时用NSFetchRequest抓取数据的时候,我们会先用NSManagedObjectContextexecuteFetchRequest:error:方法传入一个NSFetchRequest,然后请求会被发送到NSPersistentStore,然后执行一段时间后返回一个数组,在NSManagedObjectContext更新后,这个数组被当做executeFetchRequest:error:的返回值返回到我们这里。

Asynchronous Fetching则不同,当我们将一个NSAsynchronousFetchRequest对象传入executeRequest:error:方法后会立即返回一个“未来的”NSAsynchronousFetchResultNSAsynchronousFetchRequest初始化时需要传入两个参数赋值给属性:

completionBlock属性,允许我们在抓取完成后执行回调block;
fetchRequest属性,类型是NSFetchRequest。也即是说虽然是异步抓取,其实我们用的还是以前的NSFetchRequest,当NSFetchRequest抓取结束后会更新NSManagedObjectContext,这也就意味着NSManagedObjectContext的并发类型只能是NSPrivateQueueConcurrencyTypeNSMainQueueConcurrencyType
于是当我们用NSAsynchronousFetchRequest抓取数据时,我们会先用NSManagedObjectContextexecuteRequest:error:方法传入一个NSAsynchronousFetchRequest,这个方法在NSManagedObjectContext上执行时,NSManagedObjectContext会立即制造并返回一个NSAsynchronousFetchResult,同时NSAsynchronousFetchRequest会被发送到NSPersistentStore。你现在可以继续编辑这个NSManagedObjectContext中的NSManagedObject,等到NSPersistentStore执行请求完毕时会将结果返回给NSAsynchronousFetchResultfinalResult属性,更新NSManagedObjectContext,执行NSAsynchronousFetchRequest的回调block。



Realm

Realm 是个新技术。Realm比前面提到的数据库解决方案更快,更高效。它是一个跨平台的移动数据库,不仅支持Android,iOS还支持macOS,Linux,ReactNative和Xamarin。

最棒的是你通过两行代码就可以处理所有的工作。Realm相比于SQLite和Core Data而言,更易于安装并且运行的更快。

如果你正在设计一款面向很多用户,有很多记录的程序,那么你从设计的一开始就需要特别注意它的可扩展性。Realm在这方面非常出色,并且能够让你快速的操作大量数据。

想要开始使用Realm,你所需要的仅仅是最低iOS 8或者OS X 10.9的系统。早期版本的系统并不支持本地存储与数据库的全新的简单解决方案。

Realm最主要的优势是:

  • 绝对免费
  • 快速,简单的使用
  • 没有使用限制(待定)
  • 为了速度和性能,运行在自己的持久化引擎上
  • 代码量少,几乎仅仅相当于sqlite的一半代码量

缺点:

  • 类名长度最大57个UTF8字符。
  • 属性名长度最大63个UTF8字符。
  • NSDataNSString属性不能保存超过16M数据,如果有大的可以分块。
  • 对字符串进行排序以及不区分大小写查询只支持"基础拉丁字符集"、"拉丁字符补充集"、"拉丁文扩展字符集 A" 以及"拉丁文扩展字符集 B"(UTF-8 的范围在 0~591 之间)。
  • 多线程访问时需要新建新的Realm对象。
  • Realm没有自增属性。也就是说对于我们习惯的自增主键,如果确实需要,我们要自己去赋值,如果只要求独一无二, 那么可以设为[[NSUUID UUID] UUIDString],如果还要求用来判断插入的顺序,那么可以用Date。
  • Realm支持以下的属性类型:BOOL、bool、int、NSInteger、long、long long、float、double、NSString、NSDate、NSData 以及 被特殊类型标记的NSNumber,注意,不支持集合类型,只有一个集合RLMArray,如果服务器传来的有数组,那么需要我们自己取数据进行转换存储。

读取性能测试


对比图
图片来源

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容