如何有效地在Core Data中插入和获取UUID [英] How to efficient insert and fetch UUID in Core Data

查看:275
本文介绍了如何有效地在Core Data中插入和获取UUID的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种高效的方式来存储和搜索UUID在Core Data。这些UUID由分布式系统中的许多iOS设备生成。这些设备中的每一个可以存储大约20-50k个UUID。

I am looking for an efficient way to store and search UUID in Core Data. Those UUID are generated by many iOS devices in a distributed system. Each of those devices may store about 20-50k UUIDs.

很明显,在Core Data中存储UUID作为String会损害索引的效率。但是经过一系列研究后,我发现将UUID作为二进制数据存储在Core Data中(和索引)可能会比将其作为String 存储效率低。

It is obvious that storing UUID as String in Core Data will hurt the efficiency of indexing on it. But after a series of research I found that storing UUID as Binary Data in Core Data (and index it) may be less efficient than storing it as String.

由于在SQLit中没有类似于BINARY或VARBINARY的数据类型。我想Core Data中的任何二进制数据类型的数据都将作为BLOB存储在SQLit中。由于BLOB可能是最慢的数据类型被索引,它将对性能造成不良影响。

As there is no BINARY-like or VARBINARY-like data type in SQLit is supported. I guess that any Binary Data type of data in Core Data is stored as BLOB in SQLit. Since BLOB could be slowest data type to be indexed, it will cause bad influence on the performance.

所以任何人都可以帮助回答,是否有一个更有效的方式来存储核心数据中的UUID?

So can anyone help to answer, is there a more efficient way to store UUID in Core Data?

推荐答案

将其存储为ASCII字符串,并将该字段设为索引。

Store them as a ASCII string, and make the field an index.

EDIT

Egads,我碰巧正在做一些扑克,什么可耻的答案。我一定有一天的心情。如果我可以,我只是删除它,继续前进。但是,这是不可能的,所以我会提供一个更新的剪辑。

Egads, I happened to be doing some poking about, and came across this. What a shameful answer. I must have been in a bit of a mood that day. If I could, I'd just delete it and move on. However, that's not possible, so I'll provide a snip of an update.

首先,知道什么是高效的唯一方法是测量,时间和空间以及源代码复杂性和程序员的努力。

First, the only way to know what is "efficient" is to measure, considering program time and space as well as source code complexity and programmer effort.

幸运的是,这很容易。

我写了一个非常简单的OSX应用程序。该模型由一个单一的属性: identifier

I wrote a very simple OSX application. The model consists of a single attribute: identifier.

这些都不重要,如果你不标记你的属性作为索引。创建商店时需要更多的时间,但它会使查询更快。

None of this matters, if you do not mark your attribute as an index. It will take a whole lot more time when creating the store, but it will make queries much faster.

另外,注意,为二进制属性创建谓词正是与为字符串创建一样:

Also, note that creating a predicate for a binary attribute is exactly the same as creating one for a string:

fetchRequest.predicate =
    [NSPredicate predicateWithFormat:@"identifier == %@", identifier];

应用程序很简单。首先,它创建N个对象,并向标识符属性分配一个UUID。它每500个对象保存MOC。然后,我们将所有标识符存储到一个数组中,并随机地随机洗牌。

The application is very simple. First, it creates N objects, and assigns a UUID to the identifier attribute. It saves the MOC every 500 objects. We then store all identifiers into an array and randomly shuffle them. The whole CD stack is then torn down completely to remove it all from memory.

接下来,我们再次构建堆栈,然后遍历标识符,并做一个简单的取。创建fetch对象,使用一个简单的谓词来获取一个对象。所有这一切都是在autoreleasepool内完成,以保持每个fetch尽可能原始(我承认,将有一些与CD缓存的交互)。这不是那么重要,因为我们只是比较不同的技术。

Next, we build the stack again, and then iterate over the identifiers, and do a simple fetch. The fetch object is constructed, with a simple predicate to fetch that one object. All of this is done inside an autoreleasepool to keep each fetch as pristine as possible (I acknowledge that there will be some interaction with the CD caches). That's not so important, as we are just comparing the different techniques.

二进制标识符是UUID的16字节。

Binary identifier is the 16-bytes for the UUID.

UUID字符串是一个36字节字符串,是调用[uuid UUIDString]的结果,它看起来像这样(B85E91F3-4A0A-4ABB-A049-83B2A8E6085E)。

UUID String is a 36-byte string, the result of calling [uuid UUIDString], and it looks like this (B85E91F3-4A0A-4ABB-A049-83B2A8E6085E).

Base64 String是一个24字节的字符串,base-64编码16字节的UUID二进制数据的结果,对于同一个UUID,它看起来像这样(uF6R80oKSrugSYOyqOYIXg ==)。

Base64 String is a 24-byte string, the result of base-64 encoding the 16-byte UUID binary data, and it looks like this (uF6R80oKSrugSYOyqOYIXg==) for the same UUID.

Count是该运行的对象数。

Count is the number of objects for that run.

SQLite大小是实际sqlite文件的大小。

SQLite size is the size of the actual sqlite file.

WAL大小是WAL(预写日志)文件获取的大小 - 只是FYI ...

WAL size is how big the WAL (write-ahead-logging) file gets - just FYI...

Create是

查询是查询每个对象的秒数。

Query is the number of seconds to query each object.

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) - 这是数据库的预期。额外的存储量将在一定程度上相对于实际对象的大小...这只存储标识符,所以开销的百分比将更高)。

The first thing to note here is that the actual database size is much larger than the bytes stored (1,600,000 and 16,000,000) - which is to be expected for a database. The amount of extra storage will be somewhat relative to the size of your actual objects... this one only stores the identifier so the percentage of overhead will be higher).

其次,对于速度问题,作为参考,做相同的1,000,000个对象查询,但使用fetch中的object-id花了大约82秒(注意,和调用 existingObjectWithID:error: / code>花费了大量的0.3065秒)。

Second, on the speed issues, for reference, doing the same 1,000,000 object query, but using the object-id in the fetch took about 82 seconds (note the stark difference between that and calling existingObjectWithID:error: which took a whopping 0.3065 seconds).

您应该配置自己的数据库,包括明智地使用仪器上运行的代码。我想象的数字会有些不同,如果我做了多次运行,但他们非常接近,这不是必要的分析。

You should profile your own database, including a judicious use of instruments on the running code. I imagine the numbers would be somewhat different if I did multiple runs, but they are so close that it's not necessary for this analysis.

但是,基于这些数字,让我们请查看代码执行的效率测量。

However, based on these numbers, let's look at efficiency measurements for the code execution.


  • 如预期的那样,存储原始UUID二进制数据在空间方面更高效。 li>
  • 创建时间非常接近(差异似乎基于创建字符串的时间和所需的额外存储空间)。

  • 查询次数似乎几乎相同,二进制字符串似乎有点慢一点。我认为这是最初的关注 - 对一个二进制属性进行查询。

二进制获得很多空间,被认为是对创建时间和查询时间的近似。

Binary wins space by a lot, and it can be considered a close draw on both creation time and query time. If we just consider those, storing the binary data is the clear winner.

源代码复杂性和程序员时间如何?

How about source code complexity and programmer time?

好吧,如果你使用的是iOS和OSX的现代版本,几乎没有区别,尤其是在NSUUID上的一个简单类别。

Well, if you are using a modern version of iOS and OSX, there is virtually no difference, especially with a simple category on NSUUID.

是你的一个考虑,这是很容易使用数据库中的数据。当你存储二进制数据,很难得到一个很好的视觉的数据。

However, there is one consideration for you, and that's ease of using the data in the database. When you store binary data, it's hard to get a good visual on the data.

所以,如果,由于某种原因,你想要数据库中的数据被存储以更有效的方式为人类,然后将其存储为字符串是一个更好的选择。所以,你可能想考虑一个base64编码(或一些其他编码,虽然记住它已经在base-256编码)。

So, if, for some reason, you want the data in the database to be stored in a more efficient manner for humans, then storing it as a string is a better choice. So, you may want to consider a base64 encoding (or some other encoding -- though remember it's already in base-256-encoding).

FWIW,这里是一个示例类以提供更容易访问UUID作为NSData和base64字符串:

FWIW, here's an example category to provide easier access to the UUID as both NSData and base64 string:

- (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;
}

这篇关于如何有效地在Core Data中插入和获取UUID的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆