如何在Core Data中有效地插入和获取UUID
我正在寻找一种有效的方法来在Core Data中存储和searchUUID。 这些UUID是由分布式系统中的许多iOS设备生成的。 这些设备中的每一个可以存储大约20-50k的UUID。
很显然,将UUID作为string存储在核心数据中会损害索引的效率。 但经过一系列的研究后,我发现将UUID作为二进制数据存储在核心数据(和索引它)可能不如string存储效率 。
由于在SQLit中不支持类似BINARY或VARBINARY的数据types。 我猜测核心数据中的任何二进制数据types的数据在SQLit中存储为BLOB。 由于BLOB可能是最慢的数据types被索引,会对性能造成不良影响。
那么任何人都可以帮助回答,有没有一种更有效的方式来存储UUID在核心数据?
将它们存储为ASCIIstring,并将该字段设置为索引。
编辑
Egads,我碰巧正在做点什么,碰到这个。 多么可耻的答案。 那天我肯定有点心情不好。 如果可以的话,我只是删除它,继续前进。 但是,这是不可能的,所以我会提供一个更新的剪辑。
首先,要知道什么是“高效”的唯一方法就是考虑程序的时间和空间,以及源代码的复杂性和程序员的努力。
幸运的是,这个很容易。
我写了一个非常简单的OSX应用程序。 该模型由一个单一的属性: identifier
。
如果你不把你的属性标记为索引,这些都不重要。 创build商店需要花费很多时间,但会使查询速度更快。
另外,请注意,为二进制属性创build谓词与为string创build谓词完全相同:
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];
该应用程序非常简单。 首先,它创buildN个对象,并为标识符属性分配一个UUID。 它每500个物体就保存MOC。 然后,我们将所有的标识符存储到一个数组中,并随机地将其混合。 整个CD堆被完全撕下,将其全部从内存中移除。
接下来,我们再次构build堆栈,然后迭代标识符,并进行简单的获取。 获取对象被构造,用一个简单的谓词来获取这个对象。 所有这些都是在autoreleasepool内完成的,以保持每个抓取尽可能原始(我承认会有一些与CDcaching的交互)。 这并不重要,因为我们只是比较不同的技术。
二进制标识符是UUID的16个字节。
UUIDstring是一个36字节的string,是调用[uuid UUIDString]的结果,它看起来像这样(B85E91F3-4A0A-4ABB-A049-83B2A8E6085E)。
Base64string是一个24字节的string,base-64编码16字节的UUID二进制数据的结果,它看起来像这样(uF6R80oKSrugSYOyqOYIXg ==)为相同的UUID。
计数是该运行的对象的数量。
SQLite的大小是实际的sqlite文件的大小。
WAL大小是WAL(预写日志)文件的大小 – 仅供参考…
创build是创build数据库的秒数,包括保存。
查询是查询每个对象的秒数。
Data Type | Count (N) | SQLite Size | WAL Size | Create | Query --------------+-----------+-------------+-----------+---------+--------- Binary | 100,000 | 5,758,976 | 5,055,272 | 2.6013 | 9.2669 Binary | 1,000,000 | 58,003,456 | 4,783,352 | 59.0179 | 96.1862 UUID String | 100,000 | 10,481,664 | 4,148,872 | 3.6233 | 9.9160 UUID String | 1,000,000 | 104,947,712 | 5,792,752 | 68.5746 | 93.7264 Base64 String | 100,000 | 7,741,440 | 5,603,232 | 3.0207 | 9.2446 Base64 String | 1,000,000 | 77,848,576 | 4,931,672 | 63.4510 | 94.5147
首先要注意的是,实际的数据库大小比存储的字节(1,600,000和16,000,000)大得多 – 这对于数据库来说是预期的。 额外的存储量将相对于您的实际对象的大小有所…这个只存储标识符,所以开销的百分比会更高)。
其次,在速度问题上,作参考,做同样的1,000,000个对象查询,但是在获取中使用object-id需要大约82秒(注意与调用existingObjectWithID:error:
之间的明显区别existingObjectWithID:error:
花了0.3065秒) 。
您应该分析自己的数据库,包括在正在运行的代码上正确使用仪器。 我想如果我做了多次运行,这些数字会有所不同,但是它们非常接近,所以没有必要进行这种分析。
但是,基于这些数字,我们来看代码执行的效率度量。
- 正如所料,存储原始UUID二进制数据在空间方面更为有效。
- 创build时间非常接近(差异似乎是基于创buildstring的时间和所需的额外存储空间)。
- 查询时间似乎几乎完全相同,二进制string似乎慢了一点。 我认为这是最初的担心 – 对二进制属性进行查询。
Binary赢得了很多空间,可以被认为是创造时间和查询时间的一个缩影。 如果我们只考虑这些,那么存储二进制数据就是明显的赢家。
如何处理源代码的复杂性和程序员的时间?
那么,如果你使用的是iOS和OSX的现代版本,那么几乎没有什么区别,特别是在NSUUID上有一个简单的类别。
但是,您有一个需要考虑的问题,那就是在数据库中使用数据的方便性。 当您存储二进制数据时,很难获得良好的数据视觉效果。
因此,如果出于某种原因,希望数据库中的数据以更有效的方式存储在人身上,那么将其存储为string是更好的select。 所以,你可能要考虑一个base64编码(或其他编码 – 尽pipe记住它已经在base-256编码)。
FWIW,下面是一个示例类别,提供对NSData和base64string的更简单的UUID访问:
- (NSData*)data { uuid_t rawuuid; [self getUUIDBytes:rawuuid]; return [NSData dataWithBytes:rawuuid length:sizeof(rawuuid)]; } - (NSString*)base64String { uuid_t rawuuid; [self getUUIDBytes:rawuuid]; NSData *data = [NSData dataWithBytesNoCopy:rawuuid length:sizeof(rawuuid) freeWhenDone:NO]; return [data base64EncodedStringWithOptions:0]; } - (instancetype)initWithBase64String:(NSString*)string { NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0]; if (data.length == sizeof(uuid_t)) { return [self initWithUUIDBytes:data.bytes]; } return self = nil; } - (instancetype)initWithString:(NSString *)string { if ((self = [self initWithUUIDString:string]) == nil) { self = [self initWithBase64String:string]; } return self; }
- 修改核心数据模型每次都需要新版本?
- 核心数据pipe理对象上下文devisebuild议
- iOS:什么是迁移coredata关系时的值expression式函数?
- 应用程序冻结CoreData保存
- 核心数据保存对象在后台问题
- CoreData:警告:无法为实体“Readings”加载名为“WEEReadings”的类。 找不到类,使用默认的NSManagedObject来代替
- 核心数据NSManagedObject没有有效的NSEntityDescription
- 核心数据,“按瞬态sorting”的解决方法
- 我如何解决NSInternalInconsistencyException',原因:'+ entityForName:失败报告