将大型 CSV 文件加载到核心数据中的最快方法是什么

2023-11-27

结论
我想问题已经解决了。
看起来这个问题与方法无关,但 XCode 没有在构建之间正确清理项目。
看起来在所有这些测试之后,正在使用的 sqlite 文件仍然是第一个没有索引的文件......
当心 XCode 4.3.2,我除了 Clean 不清理的问题之外什么都没有,或者将文件添加到项目中时没有自动添加到捆绑资源中......
感谢您的不同答案..

Update 3
Since I invite anybody to just try the same steps to see if they get the same results, let me detail what I did:
I start with blank project
I defined a datamodel with one Entity, 3 attributes (2 strings, 1 float)
The first string is indexed
enter image description here

In did finishLaunchingWithOptions, I am calling:

[self performSelectorInBackground:@selector(populateDB) withObject:nil];

populateDb 的代码如下:

-(void)populateDB{
NSLog(@"start");
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
NSManagedObjectContext *context;
if (coordinator != nil) {
    context = [[NSManagedObjectContext alloc] init];
    [context setPersistentStoreCoordinator:coordinator];
}

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"input" ofType:@"txt"];  
if (filePath) {  
    NSString * myText = [[NSString alloc]
                               initWithContentsOfFile:filePath
                               encoding:NSUTF8StringEncoding
                               error:nil];
    if (myText) {
        __block int count = 0;


        [myText enumerateLinesUsingBlock:^(NSString * line, BOOL * stop) {
            line=[line stringByReplacingOccurrencesOfString:@"\t" withString:@" "];
            NSArray *lineComponents=[line componentsSeparatedByString:@" "];
            if(lineComponents){
                if([lineComponents count]==3){
                    float f=[[lineComponents objectAtIndex:0] floatValue];
                    NSNumber *number=[NSNumber numberWithFloat:f];
                    NSString *string1=[lineComponents objectAtIndex:1];
                    NSString *string2=[lineComponents objectAtIndex:2];
                    NSManagedObject *object=[NSEntityDescription insertNewObjectForEntityForName:@"Bigram" inManagedObjectContext:context];
                    [object setValue:number forKey:@"number"];
                    [object setValue:string1 forKey:@"string1"];
                    [object setValue:string2 forKey:@"string2"];
                    NSError *error;
                    count++;
                    if(count>=1000){
                        if (![context save:&error]) {
                            NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
                        }
                        count=0;

                    }
                }
            }



        }];
        NSLog(@"done importing");
        NSError *error;
        if (![context save:&error]) {
            NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
        }

    }  
}
NSLog(@"end");
}

其他一切都是默认的核心数据代码,没有添加任何内容。
我在模拟器中运行它。
我转到 ~/Library/Application Support/iPhone Simulator/5.1/Applications//Documents
有生成的sqlite文件

我把它复制到我的包中

我注释掉了对 populateDb 的调用

我编辑 persistenceStoreCoordinator 以在第一次运行时将 sqlite 文件从捆绑包复制到文档

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 
{
@synchronized (self)
{
    if (__persistentStoreCoordinator != nil)
        return __persistentStoreCoordinator;

    NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"myProject" ofType:@"sqlite"];
    NSString *storePath = [[[self applicationDocumentsDirectory] path] stringByAppendingPathComponent: @"myProject.sqlite"];

    NSError *error;
    if (![[NSFileManager defaultManager] fileExistsAtPath:storePath]) 
    {
        if ([[NSFileManager defaultManager] copyItemAtPath:defaultStorePath toPath:storePath error:&error])
            NSLog(@"Copied starting data to %@", storePath);
        else 
            NSLog(@"Error copying default DB to %@ (%@)", storePath, error);
    }

    NSURL *storeURL = [NSURL fileURLWithPath:storePath];

    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) 
    {

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return __persistentStoreCoordinator;
}    
}


我从模拟器中删除了该应用程序,我检查 ~/Library/Application Support/iPhone Simulator/5.1/Applications/ 现已删除
我重建并再次启动
正如预期的那样,sqlite 文件被复制到 ~/Library/Application Support/iPhone Simulator/5.1/Applications//Documents

然而,文件的大小明显小于捆绑包中的大小! 另外,使用像这样的谓词进行简单查询 predicate = [NSPredicate predicateWithFormat:@"string1 == %@", string1];清楚地表明 string1 不再被索引

接下来,我创建了一个新版本的数据模型,进行了无意义的更新,只是为了强制进行轻量级迁移
如果在模拟器上运行,迁移需要几秒钟,数据库大小加倍,并且相同的查询现在只需不到一秒即可返回,而不是几分钟。
这可以解决我的问题,强制迁移,但同样的迁移在 iPad 上需要 3 分钟,并且发生在前台。
这就是我现在所处的位置,对我来说最好的解决方案仍然是防止索引被删除,启动时任何其他导入解决方案都需要太多时间。
如果您需要更多说明,请告诉我...

Update 2
因此,到目前为止,我得到的最好结果是使用具有类似数据模型的快速工具生成的 sqlite 文件来为核心数据数据库播种,但在生成 sqlite 文件时没有设置索引。然后,我将这个 sqlite 文件导入到核心数据应用程序中并设置索引,并允许进行轻量级迁移。对于新 iPad 上的 200 万条记录,此迁移静态图像需要 3 分钟。最终应用程序的记录数应是此数量的 5 倍,因此我们仍在考虑较长的处理时间。 如果我走这条路,新的问题将是:可以在后台执行轻量级迁移吗?

Update
我的问题不是如何创建一个工具来填充核心数据数据库,然后将 sqlite 文件导入到我的应用程序中。
我知道该怎么做,我已经做过无数次了。
但直到现在,我还没有意识到这种方法可能会产生一些副作用:在我的例子中,当以这种方式导入 sqlite 文件时,结果数据库中的索引属性显然会“未索引”。
如果您能够验证任何索引数据在此类传输后仍然被索引,我很想知道您如何继续,或者有效地播种此类数据库的最佳策略是什么。

Original

我有一个大型 CSV 文件(数百万行),包含 4 列、字符串和浮点数。 这是针对 iOS 应用程序的。

我需要在第一次加载应用程序时将其加载到核心数据中。

在数据可用之前,该应用程序几乎无法运行,因此加载时间很重要,因为首次使用的用户显然不希望应用程序在能够运行之前需要 20 分钟的加载时间。

现在,我当前的代码在新 iPad 上需要 20 分钟才能处理 200 万行的 csv 文件。

我使用后台上下文来不锁定 UI,并每 1,000 条记录保存一次上下文

我的第一个想法是在模拟器上生成数据库,然后在首次启动时将其复制/粘贴到文档文件夹中,因为这是播种大型数据库的常见非官方方式。不幸的是,索引似乎无法在这样的传输中幸存下来,尽管数据库在几秒钟后就可用了,但性能很糟糕,因为我的索引丢失了。我已经发布了有关索引的问题,但似乎没有一个好的答案。

所以我正在寻找的是:

  • 一种提高核心数据加载数百万条记录性能的方法
  • 如果数据库在第一次启动时预加载并移动,这是一种保留索引的方法
  • 处理这种情况的最佳实践。我不记得使用过任何需要我在首次使用前等待 x 分钟的应用程序(但也许是《每日报》,那是一次糟糕的体验)。
  • 任何让用户在没有意识到的情况下等待的创造性方法:在完成教程时进行后台导入等......
  • 不使用核心数据?
  • ...

使用用 Cocoa 编写的离线应用程序(例如命令行实用程序)预生成数据库,该应用程序在 OS X 上运行,并使用与 iOS 相同的 Core Data 框架。您无需担心“索引存活”或任何其他问题 - 输出是 Core Data 生成的 .sqlite 数据库文件,iOS 应用程序可以直接立即使用。

只要您可以离线生成数据库,它就是迄今为止最好的解决方案。我自己已经成功地使用这种技术来预先生成用于 iOS 部署的数据库。查看我之前的问题/答案以了解更多详细信息。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将大型 CSV 文件加载到核心数据中的最快方法是什么 的相关文章

  • 条件必须具有 bool 静态类型

    有什么方法可以在这种情况下使用未来的布尔值 或者有更好的方法吗 Widget buildRow String pair final Future
  • UITableView:显示 tableFooterView 时运行代码?

    我正在使用 UIView表页脚视图 http developer apple com library ios documentation uikit reference UITableView Class Reference Referen
  • 如何将 CSV 文件读入 .NET 数据表

    如何将 CSV 文件加载到System Data DataTable 根据CSV文件创建数据表 常规 ADO net 功能是否允许这样做 我一直在使用OleDb提供者 但是 如果您正在读取具有数值的行 但希望将它们视为文本 则会出现问题 但
  • 为什么performSegueWithIdentifier在viewDidLoad中不起作用?

    我试图在视图控制器上调用 viewDidLoad 后立即触发故事板转场 Segue 附加了一个标识符 当从链接到按钮或其他控件的方法内部调用时 它可以正常工作 但它在 viewDidLoad 内部不起作用 它只是默默地失败了 viewDid
  • 核心数据:尝试查找实体中属性的最小日期

    我正在尝试查找核心数据中特定属性中最旧的日期 我发现了核心数据编程指南中的示例 http developer apple com mac library documentation cocoa conceptual CoreData Art
  • AppStore 提交:错误 ITMS-9000:“无效的捆绑结构 - 不允许二进制文件‘MyApp.app/BuildAgent’

    我陷入了以下错误 我根本不明白 错误 ITMS 9000 无效的捆绑结构 不允许使用二进制文件 MyApp app BuildAgent 您的应用程序可能只包含一个可执行文件 当我使用 Xcode 从 Archive 导出到 IPA 时 我
  • React-native-vision-camera无法访问后面的普通摄像头

    我正在尝试在 iPhone 11 Pro 上使用 普通 相机 我使用反应本机视觉相机 当我运行这段代码时 const devices useCameraDevices const deviceBack devices back consol
  • Objective-C UILabel 作为超链接

    我正在尝试做一个UILabel一个链接UIWebView 我怎样才能做一个UILabel作为超链接 您可以使用 UITapGestureRecognizer 它将实现与您想要的类似的功能 UILabel myLabel UILabel al
  • SQLite更新第一个字母为大写

    我有一个字段 customer country 我正在尝试更新它 以便国家 地区值的第一个字母为大写 我似乎无法找到一种方法来做到这一点 UPDATE customer SET country UPPER SUBSTR country 1
  • Swift,以编程方式更改 UICollectionViewCell 和 UILabel(单元格内)的宽度

    我已将单元格 UICollectionViewCell 的宽度设置为等于 UICollectionView 的宽度 并且我尝试对该单元格中包含的 UILabel 执行完全相同的操作 我认为下面的代码准确地解释了我想要实现的目标 所以我在这里
  • sqlite 列名称引用(功能或错误)

    我遇到了一些对我来说看起来很奇怪的东西 但可能是我滥用了 sqlite3 create table t v 0 text insert into t values aa select from t v aa pragma table inf
  • 使用未解析的标识符“FlurryAdInterstitial”

    我正在尝试整合Flurry Interstitial Ads使用cocoapods in Swift and Xcode 7 1 1 我正在关注开发人员雅虎网站上的此文档 https developer yahoo com flurry d
  • 会话重新启动后 AVcapture 会话启动缓慢

    我有一个主视图控制器 它连接到具有 avcapturesession 的第二个视图控制器 我第一次从主视图控制器转向捕获会话控制器 大约需要 50 毫秒 使用 仪器 检查 然后我从捕获会话返回到主视图控制器 然后从主控制器返回到 avcap
  • 调整 UIImage 的大小而不将其完全加载到内存中?

    我正在开发一个应用程序 用户可以在其中尝试加载非常非常大的图像 这些图像首先在表格视图中显示为缩略图 我的原始代码会在大图像上崩溃 因此我重写它以首先将图像直接下载到磁盘 是否有一种已知的方法可以调整磁盘上图像的大小 而无需通过以下方式将其
  • 如何在代码中编辑约束

    我有一个以 100 开始宽度限制的网页 当用户单击按钮时 我想将约束更改为 200 我试过这个 NSLayoutConstraint constrain NSLayoutConstraint constraintWithItem self
  • UIView 圆角 - Swift 2.0?

    我会尝试将一些项目更新到 Swift 2 0 我有一个视图 左上角有一个圆角 在 Swift 没有警告 没有错误 只是没有圆角 这就是它在 Swift let maskPath UIBezierPath roundedRect conten
  • 如何在 UICollectionView 中将行居中?

    我有一个UICollectionView与随机细胞 有什么方法可以让我将行居中吗 默认情况下它是这样的 x x x x x x x x x x x x x x 这是所需的布局 x x x x x x x x x x x x 我必须做这样的事
  • SQLite-Net 扩展 - GetAllWithChildrenAsync 未提取所有内容

    我正在尝试使用 SQLite Net 扩展来创建关系数据库 我在尝试从数据库中提取 Term 对象时遇到了问题 它成功地撤回了其关联的课程 但未撤回与课程关联的评估和笔记 我不确定问题是否在于如何将对象插入数据库 如何从数据库中提取对象 或
  • 更改 iOS7 中 UIAlertView 的字体大小

    我想更改alertView中消息文本和标题文本的字体大小 苹果网站上没有任何文档谈到这一点 但苹果在其子类注释中表示 UIAlertView 类旨在按原样使用 请参考以下链接 https developer apple com librar
  • ios - 如何声明静态变量? [复制]

    这个问题在这里已经有答案了 C 中声明的静态变量如下 private const string Host http 80dfgf7c22634nbbfb82339d46 cloudapp net private const string S

随机推荐