【问题标题】:Core Data Fetch Very Slow on iPadiPad 上的核心数据获取速度非常慢
【发布时间】:2011-05-04 20:55:28
【问题描述】:

我在使用 iOS 4.3.2 的 iPad 上运行了以下核心数据获取请求。

NSPredicate *predicate = [NSPredicate predicateWithFormat:
                          @"feed.account.name == %@ AND feed.feedType == %@", accountName,feedType];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" 
                                                               ascending:NO];

NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];

fetchedResultsController=[self createFetchedResultsController:@"RssFeedItem"  predicate:predicate sortDescriptors:sortDescriptors];

[fetchedResultsController.fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:@"url",@"headline",@"isRead",@"origin",@"originId",@"date",nil]];


[fetchedResultsController.fetchRequest setFetchLimit:500];

[fetchedResultsController setDelegate:self];

[fetchedResultsController performFetch:&error];

return [fetchedResultsController fetchedObjects];

我在 RssFeedItem 表的 SQLite 数据库中有大约 688 行数据,而在所有其他表中不到 100 行。该查询使用调试日志记录为:

CoreData: sql: SELECT t0.Z_ENT, t0.Z_PK, t0.ZURL, t0.ZHEADLINE, t0.ZISREAD, t0.ZORIGIN,           
CoreData: annotation: sql connection fetch time: 3.3854s
CoreData: annotation: total fetch execution time: 3.4178s for 688 rows.

而且运行速度非常慢(超过 3 秒)。我对所有必需的搜索字段和排序字段都有索引。我假设也许 2 方式加入让它变慢了,但不知道为什么它会那么慢。有什么方法可以优化此代码或查询,还是我应该查看其他内容?

【问题讨论】:

    标签: ios core-data ipad


    【解决方案1】:

    我猜你的查询速度变慢的行是

     [fetchedResultsController.fetchRequest setPropertiesToFetch:[NSArray 
     arrayWithObjects:@"url",@"headline",@"isRead",@"origin",@"originId",@"date",nil]];
    

    [fetchedResultsController.fetchRequest setFetchLimit:500];
    

    我很好奇,为什么您需要一次获取所有这些属性(和 500 个项目)?

    【讨论】:

    • 另外,我同意@McCygnus,重新排序你的谓词可能会有所作为。
    • 我认为这不是问题,因为我有其他应用程序具有更大的数据库并且获取 500 行非常快。这个数据库很小(总共不到 1000 行),所以我看不出它如何需要 3 秒。我可以在几毫秒内在内存中创建 500 个全新的对象。我也可以非常快速地枚举数据库中的所有对象(不使用查询/谓词等) - 生成的查询似乎只是被核心数据或 SQLlite 处理得很差。
    • 但是这个查询不仅仅是枚举或读取索引,它实际上是从磁盘读取数据。 (这可能是一个糟糕的实现,我自己并不喜欢 CoreData。)不过,这个查询需要从磁盘读取 500*6 = 3000 个字符串,创建 3000 个 nsstring,并用数据填充它们。我认为不是那么微不足道。
    【解决方案2】:

    这似乎有点慢。我不知道这是否会产生巨大的速度差异,但它应该会有所帮助,将您的谓词修改为:

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"feed.feedType == %@ AND feed.account.name == %@", feedType, accountName];
    

    您希望将最便宜的条件放在首位,这样就不必在所有情况下都检查更昂贵的条件。检查帐户名称时发生的加入要昂贵得多。此外,根据提要类型值的样子,将其切换为整数可能会更快(我假设它当前是一个字符串,因为它是一个对象)。

    【讨论】:

    • 谢谢,有道理,所以我先试试这个。
    • 我尝试按照上面的说明重新排列谓词。但是还是很慢:CoreData: sql: SELECT t0.Z_ENT, t0.Z_PK, t0.ZURL, t0.ZHEADLINE, t0.ZISREAD, t0.ZORIGIN, t0.ZORIGINID, t0.ZDATE FROM ZFEEDITEM t0 JOIN ZFEED t1 ON t0.ZFEED = t1.Z_PK JOIN ZFEEDACCOUNT t2 ON t1.ZACCOUNT = t2.Z_PK WHERE (( t1.ZFEEDTYPE = ? AND t2.ZNAME = ?) AND t0.Z_ENT = ?) ORDER BY t0.ZDATE DESC LIMIT 500CoreData: annotation: sql connection fetch time: 4.0500sCoreData: annotation: total fetch execution time: 4.0797s for 500 rows.
    • 您的谓词仍然会很慢,因为其中发生了 2 个连接。您可能需要重构模型以对其进行重大改进。发布您的模型,我们也许可以就改进它提出一些建议。基本上,您希望在要获取的实体中尽可能多地而不是关系中的谓词中检查值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-08
    • 1970-01-01
    • 1970-01-01
    • 2020-04-27
    • 2020-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多