将它们存储为ASCII字符串,并将字段设置为索引。
编辑:
天哪,我碰巧在瞎逛时发现了这个。真是个丢人的回答。那天可能心情有点不好。如果可以的话,我会直接删除并继续前进。但很遗憾,这是不可能的,所以我会提供一个更新的片段。
首先,了解什么是“高效”的唯一方法就是进行测量,考虑程序时间和空间以及源代码复杂性和程序员的努力。
幸运的是,这个问题相当简单。
我编写了一个非常简单的OSX应用程序。模型只包含一个属性:identifier。
如果您不将属性标记为索引,则所有这些都无关紧要。创建存储时需要更多时间,但查询速度会更快。
此外,请注意,为二进制属性创建谓词与为字符串创建谓词完全相同。
fetchRequest.predicate =
[NSPredicate predicateWithFormat:@"identifier == %@", identifier]
应用程序非常简单。首先,它创建N个对象,并为标识属性分配一个UUID。每500个对象保存一次MOC。然后,我们将所有标识符存储到一个数组中,并对它们进行随机洗牌。整个CD堆栈被完全拆除,以将其从内存中移除。
接下来,我们重新构建堆栈,然后迭代标识符,并进行简单的获取操作。获取对象是通过构造一个简单的谓词来获取一个对象。所有这些都在自动释放池中完成,以尽可能保持每次获取的纯净性(我承认与CD缓存会有一些交互)。这并不是很重要,因为我们只是在比较不同的技术。
二进制标识符是UUID的16字节。
UUID字符串是一个36字节的字符串,调用[uuid UUIDString]的结果,它看起来像这样(B85E91F3-4A0A-4ABB-A049-83B2A8E6085E)。
Base64字符串是一个24字节的字符串,是对16字节UUID二进制数据进行Base64编码的结果,它看起来像这样(uF6R80oKSrugSYOyqOYIXg==),对应相同的UUID。
计数是该运行中对象的数量。
SQLite大小是实际sqlite文件的大小。
WAL大小是WAL(预写式日志)文件的大小 - 只是提供信息...
创建是创建数据库所需的秒数,包括保存。
查询是查询每个对象所需的秒数。
数据类型 |
数量 (N) |
SQLite 大小 |
WAL 大小 |
创建时间 |
查询时间 |
二进制 |
100,000 |
5,758,976 |
5,055,272 |
2.6013 |
9.2669 |
二进制 |
1,000,000 |
58,003,456 |
4,783,352 |
59.0179 |
96.1862 |
UUID 字符串 |
100,000 |
10,481,664 |
4,148,872 |
3.6233 |
9.9160 |
UUID 字符串 |
1,000,000 |
104,947,712 |
5,792,752 |
68.5746 |
93.7264 |
Base64 字符串 |
100,000 |
7,741,440 |
5,603,232 |
3.0207 |
9.2446 |
Base64 字符串 |
1,000,000 |
77,848,576 |
4,931,672 |
63.4510 |
94.5147 |
首先要注意的是,实际数据库的大小要比存储的字节数(1,600,000和16,000,000)大得多 - 这在数据库中是可以预料的。额外存储量将与实际对象的大小有关...这个数据库只存储标识符,因此开销的百分比会更高。
其次,在速度问题上,作为参考,使用对象ID进行查询相同的1,000,000个对象,需要大约82秒(请注意与调用
existingObjectWithID:error:
相比,后者仅需0.3065秒的巨大差异)。
您应该对自己的数据库进行性能分析,包括对运行代码使用适当的工具。我想如果我进行多次运行,这些数字可能会有所不同,但它们非常接近,对于这个分析来说并不必要。
然而,基于这些数字,让我们来看一下代码执行的效率测量。
- 正如预期的那样,以原始UUID二进制数据存储在空间上更有效率。
- 创建时间非常接近(差异似乎基于创建字符串的时间和额外的存储空间所需)。
- 查询时间几乎相同,二进制字符串稍微慢一点。我想这是最初的担忧——对二进制属性进行查询。
二进制在空间上占优势,并且在创建时间和查询时间上可以被视为接近平局。如果只考虑这些因素,存储二进制数据是明显的赢家。
那么源代码复杂性和程序员时间呢?
嗯,如果你正在使用现代版本的iOS和OSX,几乎没有区别,尤其是在NSUUID的简单类别上。
然而,有一个考虑因素,那就是在数据库中使用数据的便利性。当你存储二进制数据时,很难对数据进行良好的可视化。
因此,如果出于某种原因,你希望数据库中的数据以更高效的方式存储,供人类使用,那么将其存储为字符串是一个更好的选择。因此,你可能需要考虑使用base64编码(或其他编码方式——但请记住它已经是基于256的编码)。
FWIW,这是一个示例类别,以便更轻松地访问UUID,同时提供NSData和base64字符串的形式:
- (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;
}