索引日期类型的核心数据属性是否有意义?

Does it make sense to index a core data attribute of type date?

由于日期类型的核心数据模型属性包含日期和时间,对其进行索引是否有意义?在其他数据库环境中,我认为最好不要为唯一值太少或太多的属性编制索引。

在我的特殊情况下,绝大多数日期将为零。我的谓词如下所示:

NSPredicate *subPredicate = [NSPredicate predicateWithFormat:@"xDate == nil || xDate < %@", [NSDate date]];

目前我的 xDate 字段没有编入索引,典型的提取需要大约 2.4 秒,对于只有 1300 条返回记录的 IMO 来说太长了。

是的,它肯定会固定查询结果。我试过了。

我有一个大数据,结果是 - 无索引 ~ 2 秒 带索引 ~ .2 - .3 秒

经过数小时的调试和分析,我得出的结论是,如果索引确定有更好的方法,您就不能让核心数据使用索引。

这个 blog post 帮助我理解了如何使用 SQLite 的 EXPLAIN QUERY PLAN 来分析用于执行提取的策略。

基本上,我所做的是:

在Xcode中:

  • 在我的运行方案中设置-com.apple.CoreData.SQLDebug 1
  • 设置持久存储后记录我的 .sqlite 数据库位置。我这样做是因为 iOS 8 模拟器路径随每次安装而变化。

在终端中:

  • 打开终端并执行/usr/bin/sqlite3
  • 在 sqlite> 提示符下,我发出了一个 .open 命令,其中包含我之前登录到调试器控制台的数据库路径。我这样做是因为我有多个持久存储。
  • 在 sqlite> 提示符下,我执行了 EXPLAIN QUERY PLAN 和 SQL select 语句,com.apple.CoreData.SQLDebug 记录到调试器控制台。

您还可以向 sqlite3 发出 .indices 命令来验证您的索引是否符合预期。

显然,这仅适用于模拟器,因为您无法从终端打开设备上的数据库。

为了更轻松地在多个数据存储和模拟器位置之间移动,我在设置持久存储后调用此方法:

- (void)examineQuery
{
    NSMutableString *result = [NSMutableString string];
    [result appendString: @"\n/usr/bin/sqlite3"];
    [result appendFormat: @"\n.open '%@'", [self.coreDataStack.databaseURL path]];
    [result appendString: @"\nEXPLAIN QUERY PLAN "];
    NSLog(@"%@",result);
}

我只是从调试器中复制所有 3 行并将它们粘贴到终端中。然后我在调试器中找到记录的 SELECT 语句,将其复制并粘贴到终端中。您需要在完成的 EXPLAIN QUERY PLAN 命令末尾键入 ;,以便 sqlite3 终止输入并处理命令。

在我的例子中,sqlite3 EXPLAIN QUERY PLAN 给出了这个结果:

SCAN TABLE ZART AS t0 USING INDEX ZART_ZNAME_INDEX

好的,它正在使用不同的索引。看看我的 NSFetchRequest,我现在可以假设排序描述符正在确定索引。

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:kEntityName];
request.sortDescriptors = [NSArray arrayWithObjects:
                           [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)],
                           nil];

我更改了我的代码以保证 xDate 永远不会为 NULL,以确定 OR 子句是否导致核心数据不使用我在 xDate 上的索引。我现在能够使 xDate 在模型中不可选并更改我的谓词:

[NSPredicate predicateWithFormat:@"xDate > %@", [NSDate date]]

sqlite3 EXPLAIN QUERY PLAN 给出了相同的结果:

SCAN TABLE ZART AS t0 USING INDEX ZART_ZNAME_INDEX

我尝试的最后一件事是在 xDate,name 上创建复合索引。再次经历 EXPLAIN QUERY PLAN 过程产生了相同的结果。

在我的调查过程中,我发现了多个对核心数据优化提取的引用,但没有保证索引的使用。我假设那是我撞到的墙。

奇怪的是,即使没有使用 xDate 和 xDate,name 索引,我的抓取时间现在也减少到了 0.21 秒。我相信改进来自从模拟器中删除我的应用程序并进行全新安装。我所有的索引使用测试都是在新的应用程序安装之后完成的(在你问之前 ;)

向我的模型添加索引似乎没有传播到已安装的数据库。我确实先尝试迁移到新版本的数据库,但它似乎仍然没有添加新的指标。