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

Posted

技术标签:

【中文标题】索引日期类型的核心数据属性是不是有意义?【英文标题】:Does it make sense to index a core data attribute of type date?索引日期类型的核心数据属性是否有意义? 【发布时间】:2015-02-09 23:50:43 【问题描述】:

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

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

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

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

【问题讨论】:

@Ian,我做了,但似乎得到了不一致的基准。我也不知道对索引大小有什么影响 【参考方案1】:

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

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

基本上,我所做的是:

在 Xcode 中:

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

在终端:

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

您也可以向 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 秒。我相信改进来自于从模拟器中删除我的应用程序并进行全新安装。我所有的索引使用测试都是在新应用安装后完成的(在你问之前;)

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

【讨论】:

【参考方案2】:

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

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

【讨论】:

感谢您的回复。我绝对没有看到可衡量的差异。想知道它是否是谓词中的 OR。核心数据生成 SQL where 子句:WHERE ( t0.ZXDATE IS NULL OR t0.ZXDATE

以上是关于索引日期类型的核心数据属性是不是有意义?的主要内容,如果未能解决你的问题,请参考以下文章

运行比核心数量更多的分区是不是有意义?

核心数据。按日期过滤

日期时间字段上的 MySQL 索引不是 RANGE 类型,而是使用 INDEX 类型

数据挖掘-认识数据

核心数据保存日期错误

Mysql: mysql between 日期索引 索引问题-日期索引使用