索引日期类型的核心数据属性是否有意义?
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 秒。我相信改进来自从模拟器中删除我的应用程序并进行全新安装。我所有的索引使用测试都是在新的应用程序安装之后完成的(在你问之前 ;)
向我的模型添加索引似乎没有传播到已安装的数据库。我确实先尝试迁移到新版本的数据库,但它似乎仍然没有添加新的指标。
由于日期类型的核心数据模型属性包含日期和时间,对其进行索引是否有意义?在其他数据库环境中,我认为最好不要为唯一值太少或太多的属性编制索引。
在我的特殊情况下,绝大多数日期将为零。我的谓词如下所示:
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 秒。我相信改进来自从模拟器中删除我的应用程序并进行全新安装。我所有的索引使用测试都是在新的应用程序安装之后完成的(在你问之前 ;)
向我的模型添加索引似乎没有传播到已安装的数据库。我确实先尝试迁移到新版本的数据库,但它似乎仍然没有添加新的指标。