Jaki jest najszybszy sposób załadowania dużego pliku CSV do danych podstawowych

Wniosek
Myślę, że problem został zamknięty.
Wygląda na to, że problem nie miał nic wspólnego z metodologią, ale że XCode nie czyścił projektu poprawnie między kompilacjami.
Wygląda na to, że po tych wszystkich testach używany plik sqlite był nadal pierwszym, który nie był indeksowany ......
Uważaj na XCode 4.3.2, mam tylko problemy z Clean not cleaning lub dodaniem plików do projektu, który nie jest automatycznie dodawany do zasobów pakietu ...
Dziękujemy za różne odpowiedzi ..

Aktualizacja 3
Ponieważ zapraszam wszystkich do wypróbowania tych samych kroków, aby sprawdzić, czy uzyskują te same wyniki, pozwól mi podać szczegóły tego, co zrobiłem:
Zaczynam od pustego projektu
Zdefiniowałem model danych z jedną Jednostką, 3 atrybutami (2 łańcuchy, 1 zmiennoprzecinkowy)
Pierwszy ciąg jest indeksowany


W nie skończyłem LaunchingWithOptions, dzwonię:

<code>[self performSelectorInBackground:@selector(populateDB) withObject:nil];
</code>

Kod populateDb jest poniżej:

<code>-(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");
}
</code>

Wszystko inne to domyślny podstawowy kod danych, nic nie zostało dodane.
Uruchomię to w symulatorze.
Idę do ~ / Library / Application Support / iPhone Simulator / 5.1 / Applications // Documents
Generowany jest plik sqlite

Biorę to i kopiuję to w moim pakiecie

Komentuję wezwanie do wypełnienia Db

Edytuję persistentStoreCoordinator, aby skopiować plik sqlite z pakietu do dokumentów przy pierwszym uruchomieniu

<code>- (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;
}    
}
</code>


Usuwam aplikację z symulatora, sprawdzam, czy ~ / Library / Application Support / iPhone Simulator / 5.1 / Applications / jest teraz usunięty
Odbudowuję i uruchamiam ponownie
Zgodnie z oczekiwaniami, plik sqlite jest kopiowany do ~ / Library / Application Support / iPhone Simulator / 5.1 / Applications // Documents

Jednak rozmiar pliku jest znacznie mniejszy niż w pakiecie! Również wykonanie prostego zapytania z predykatem takim jak ten predykat = [NSPredicate predicateWithFormat: @ "string1 ==% @", string1]; wyraźnie pokazuje, że string1 nie jest już indeksowany

Następnie tworzę nową wersję modelu danych z bezsensowną aktualizacją, aby wymusić lekką migrację
W przypadku uruchomienia na symulatorze migracja zajmuje kilka sekund, baza danych podwaja się, a to samo zapytanie trwa mniej niż sekundę, a nie minuty.
To rozwiąże mój problem, wymusi migrację, ale ta sama migracja trwa 3 minuty na iPadzie i dzieje się na pierwszym planie.
Tak więc tam, gdzie jestem teraz, najlepszym rozwiązaniem dla mnie byłoby nadal zapobieganie usuwaniu indeksów, każde inne rozwiązanie importowe w czasie uruchamiania zajmuje zbyt dużo czasu.
Daj mi znać, jeśli potrzebujesz więcej wyjaśnień ...

Aktualizacja 2
Najlepszym wynikiem, jaki do tej pory osiągnąłem, jest zasianie podstawowej bazy danych za pomocą pliku sqlite utworzonego z szybkiego narzędzia o podobnym modelu danych, ale bez indeksów ustawionych podczas tworzenia pliku sqlite. Następnie importuję ten plik sqlite w podstawowej aplikacji danych z ustawionymi indeksami i pozwalam na lekką migrację. W przypadku rekordu 2 milionów na nowym iPadzie zdjęcia migrujące trwają 3 minuty. Ostateczna aplikacja powinna mieć pięciokrotnie większą liczbę rekordów, więc wciąż szukamy długiego czasu przetwarzania. Gdybym poszedł tą trasą, pojawiłoby się nowe pytanie: czy można wykonać lekką migrację w tle?

Aktualizacja
Moje pytanie NIE dotyczy sposobu tworzenia narzędzia do wypełnienia bazy danych Core Data, a następnie importowania pliku sqlite do mojej aplikacji.
Wiem, jak to zrobić, robiłem to niezliczoną ilość razy.
Ale do tej pory nie zdawałem sobie sprawy, że taka metoda może mieć jakiś efekt uboczny: w moim przypadku indeksowany atrybut w wynikowej bazie danych wyraźnie „nieindeksowany” podczas importowania pliku sqlite w ten sposób.
Jeśli byłbyś w stanie zweryfikować, że po indeksacji nadal są indeksowane jakieś indeksowane dane, interesuje mnie, jak postępujesz, lub w inny sposób, jaka byłaby najlepsza strategia efektywnego rozsiewania takiej bazy danych.

Oryginalny

Mam duży plik CSV (miliony linii) z 4 kolumnami, ciągami znaków i zmiennoprzecinkowymi. To jest dla aplikacji na iOS.

Potrzebuję tego do załadowania do danych podstawowych po pierwszym załadowaniu aplikacji.

Aplikacja nie działa zbyt długo, dopóki dane nie będą dostępne, więc czas ładowania ma znaczenie, ponieważ pierwszy użytkownik najwyraźniej nie chce, aby aplikacja zajęła 20 minut na załadowanie, zanim będzie mogła go uruchomić.

Obecnie mój obecny kod trwa 20 minut na nowym iPadzie, aby przetworzyć 2 miliony wierszy pliku csv.

Używam kontekstu tła, aby nie blokować interfejsu użytkownika i zapisywać kontekst co 1000 rekordów

Pierwszym pomysłem, jaki miałem, było wygenerowanie bazy danych na symulatorze, a następnie skopiowanie / wklejenie jej do folderu dokumentu przy pierwszym uruchomieniu, ponieważ jest to powszechny, nieoficjalny sposób rozsiewania dużej bazy danych. Niestety, indeksy nie zdają się przetrwać takiego transferu i chociaż baza danych była dostępna już po kilku sekundach, wydajność jest straszna, ponieważ moje indeksy zostały utracone. Wysłałem już pytanie o indeksy, ale wydaje się, że nie ma na to dobrej odpowiedzi.

Więc czego szukam:

sposób na zwiększenie wydajności przy ładowaniu milionów rekordów w podstawowych danychjeśli baza danych jest wstępnie załadowana i przeniesiona przy pierwszym uruchomieniu, sposób na zachowanie moich indeksównajlepsze praktyki postępowania z tego rodzaju scenariuszem. Nie przypominam sobie, żebym używał jakiejkolwiek aplikacji, która wymaga ode mnie czekania przez x minut przed pierwszym użyciem (ale może The Daily, a to było straszne doświadczenie).Dowolny kreatywny sposób na sprawienie, aby użytkownik poczekał bez jego uświadomienia sobie: importowanie tła podczas przechodzenia przez samouczek itp.Nie korzystasz z podstawowych danych?...

questionAnswers(2)

yourAnswerToTheQuestion