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

结论
问题结束了,我想。
看起来这个问题与这个方法无关,但是XCode没有在两个版本之间正确地清理项目。
看起来像所有这些testing,正在使用的SQLite文件仍然是第一个没有索引的…
当心XCode 4.3.2,我没有任何东西,但没有问题清洁不清洁,或添加文件项目不会自动添加到束资源…
感谢不同的答案..

更新3
由于我邀请任何人只是尝试相同的步骤,看看他们是否得到相同的结果,让我详细说明我做了什么:
我从空白项目开始
我定义了一个实体的数据模型,3个属性(2个string,1个浮点数)
第一个string被索引
在这里输入图像说明

在完成了LaunchingWithOptions之后,我打电话给:

[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"); } 

其他一切都是默认的核心数据代码,什么也没加。
我在模拟器中运行它。
我去〜/图书馆/应用程序支持/ iPhone模拟器/ 5.1 /应用程序/ /文档
有生成的sqlite文件

我拿这个,我把它复制在我的包里

我注释掉了populateDb的调用

我编辑persistentStoreCoordinator复制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; } } 

我从模拟器中删除应用程序,我检查〜/库/应用程序支持/ iPhone模拟器/ 5.1 /应用程序/现在被删除
我重build并重新启动
正如所料,sqlite文件被复制到〜/库/应用程序支持/ iPhone模拟器/ 5.1 /应用程序/ /文档

然而,文件的大小比捆绑中的小,显着! 另外,用这样的谓词做一个简单的查询:[NSPredicate predicateWithFormat:@“string1 ==%@”,string1]; 清楚地表明string1不再索引

接下来,我创build了一个新版本的数据模型,并进行了无意义的更新,以强制轻量级迁移
如果在模拟器上运行,迁移需要几秒钟的时间,数据库的大小加倍,同样的查询现在需要不到一秒的时间来返回而不是分钟。
这将解决我的问题,强制迁移,但同样的迁移在iPad上需要3分钟,发生在前台。
因此,我现在所处的位置,对我来说,最好的解决scheme仍然是防止索引被删除,在启动时任何其他导入解决scheme只需要很多时间。
让我知道如果你需要更多的澄清…

更新2
所以迄今为止我所得到的最好的结果是将核心数据数据库与使用类似数据模型的快速工具生成的sqlite文件结合起来,但在生成sqlite文件时没有设置索引。 然后,我将这个sqlite文件导入核心数据应用程序,并设置索引,并允许轻量级的迁移。 对于新iPad上的200万条logging,这个迁移仍然需要3分钟。 最终的应用程序应该有这个logging数的5倍,所以我们仍然看着很长的处理时间。 如果我走这条路,新的问题将是:轻量级的迁移可以在后台执行吗?

更新
我的问题不是如何创build一个工具来填充核心数据数据库,然后将sqlite文件导入到我的应用程序。
我知道如何做到这一点,我做了无数次。
但直到现在,我还没有意识到这样的方法可能会有一些副作用:在我的情况下,在导入sqlite文件的时候,结果数据库中的索引属性显然会被“取消索引”。
如果您能够validation任何索引数据在转移之后仍然被编入索引,那么我有兴趣知道您是如何继续的,否则最有效的方法是build立这样的数据库。

原版的

我有一个很大的CSV文件(数百万行)与4列,string和浮游物。 这是一个iOS应用程序。

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

这个应用程序在数据可用之前几乎没有任何function,所以加载时间很重要,因为第一次用户显然不希望应用程序花20分钟才能运行它。

现在,我目前的代码在新的iPad上花费20分钟来处理一个200万行的csv文件。

我正在使用后台上下文来不locking用户界面,并保存上下文每1,000条logging

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

所以我在找什么:

  • 一种提高核心数据中数百万条logging的性能的方法
  • 如果数据库是在第一次启动时被预先加载并移动的,一种保留我的索引的方法
  • 处理这种情况的最佳实践。 我不记得使用任何需要我在第一次使用前等待x分钟的应用程序(但也许是“每日”,这是一个可怕的经历)。
  • 任何创造性的方式,让用户等待,他没有意识到:通过教程等背景导入…
  • 不使用核心数据?

使用Cocoa编写的脱机应用程序(比如命令行工具)预先生成数据库,该应用程序在OS X上运行,并使用iOS使用的相同Core Data框架。 您不必担心“索引存活”或其他任何事情 – 输出是一个由Core Data生成的.sqlite数据库文件,可直接由iOS应用程序立即使用。

只要您可以离线创build数据库,这是迄今为止最好的解决scheme。 我已经成功地使用这种技术为我自己的iOS部署预先生成的数据库。 检查我以前的问题/答案了解更多的细节。

我刚刚开始与SQLite,我需要将数据库集成到我的应用程序之一,将在SQLite数据库中有很多索引数据。 我希望我可以做一些方法,我可以批量插入我的信息到SQLite文件,并将该文件添加到我的项目。 在发现并阅读了您的问题,提供的答案和众多评论之后,我决定查看SQLite源代码,看看是否可以解决这个问题。

我最初的想法是,SQLite的iOS实现,实际上是抛出你的指数。 原因是因为您最初在x86 / x64系统上创build数据库索引。 iOS是ARM处理器,数字处理方式不同。 如果你希望你的索引速度很快,你应该以这样一种方式生成它们,以便它们被优化用于search它们的处理器。

由于SQLite是用于多个平台的,因此它将删除在另一个体系结构中创build的任何索引并重build它们。 但是,由于没有人希望等待索引重新初始化访问,SQLite开发人员最可能决定放弃索引。

深入SQLite代码后,我得出结论,这是最有可能发生的。 如果不是处理器体系结构的原因,我find了代码(参见sqliteint.h中的sqliteint.h和其他元信息),如果在意外的情况下生成索引,索引将被删除。 我的直觉是驱动这个过程的上下文是如何为现有的密钥构造底层b-tree数据结构。 如果SQLite的当前实例无法使用密钥,则会将其删除。

值得一提的是,iOS模拟器就是一个模拟器。 它不是硬件的仿真器。 因此,您的应用程序正在运行在x86 / x64处理器上的伪iOS设备中运行。

当您的应用程序和SQLite数据库加载到您的iOS设备时,将加载一个ARM编译的变体,该变体也链接到iOS中的ARM编译库。 我无法find与SQLite相关的ARM特定代码,所以我想苹果不得不修改它的西装。 这也可能是问题的一部分。 这可能不是root-SQLite代码的问题,这可能是Apple / ARM编译版本的问题。

我能想出的唯一合理的解决scheme是您可以创build一个在iOS机器上运行的生成器应用程序。 运行应用程序,构build密钥,然后从设备中翻录SQLite文件。 我想这样的文件可以在所有设备上运行,因为iOS使用的所有ARM处理器都是32位的。

再一次,这个答案是有点教育的猜测。 我将重新标记为SQLite的问题。 希望大师可以find这个,并能够在这个问题上权衡。 为了我自己的利益,我真的很想知道真相。

    Interesting Posts