2012-05-04 36 views
6

Kết luận
Sự cố đã đóng, tôi nghĩ vậy.
Có vẻ như vấn đề không liên quan gì đến phương pháp luận, nhưng XCode không làm sạch dự án một cách chính xác giữa các bản dựng.
Dường như sau tất cả các thử nghiệm đó, tệp sqlite đã được sử dụng vẫn là tệp đầu tiên không được lập chỉ mục ......
Cẩn thận với XCode 4.3.2, tôi không có gì ngoài vấn đề với Sạch không làm sạch, hoặc thêm các tập tin dự án không tự động được thêm vào các nguồn tài nguyên bó ...
Cảm ơn câu trả lời khác nhau ..Cách nhanh nhất để tải tệp CSV lớn vào dữ liệu chính là gì

cập nhật 3
Kể từ khi tôi mời ai chỉ cần thử các bước tương tự để xem nếu họ nhận được kết quả tương tự, hãy để tôi chi tiết những gì tôi đã làm:
Tôi bắt đầu với dự án trống
tôi xác định một DataModel với một Entity, 3 thuộc tính (2 dây, 1 phao)
Chuỗi đầu tiên được lập chỉ mục
enter image description here

Trong đã finishLaunchingWithOptions, tôi kêu gọi:

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

Mã cho populateDb bên dưới:

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

Mọi thứ khác là mã dữ liệu cốt lõi mặc định, không có gì được thêm vào.
Tôi chạy điều đó trong trình mô phỏng.
tôi đi đến ~/Library/Application Support/iPhone Simulator/5.1/Applications // Documents
Có file sqlite được tạo

Tôi lấy điều đó và tôi sao chép nó trong bó của tôi

tôi bình luận ra lời kêu gọi populateDb

tôi sửa persistentStoreCoordinator để sao chép các tập tin SQLite từ bó với các tài liệu tại chạy đầu tiên

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


Tôi xóa ứng dụng khỏi trình mô phỏng, tôi kiểm tra xem ~/Library/Application Support/iPhone Simulator/5.1/Applications/hiện đã bị xóa
Tôi tạo lại và khởi chạy lại
Như dự kiến, tệp sqlite được sao chép sang ~/Library/Hỗ trợ ứng dụng/Trình mô phỏng iPhone/5.1/Ứng dụng // Tài liệu

Tuy nhiên kích thước của tệp nhỏ hơn trong gói, đáng kể! Ngoài ra, thực hiện truy vấn đơn giản với biến vị ngữ như vị từ này = [NSPredicate predicateWithFormat: @ "string1 ==% @", string1]; rõ ràng cho thấy rằng chuỗi1 không lập chỉ mục nữa

Sau đó, tôi tạo ra một phiên bản mới của DataModel, với một bản cập nhật vô nghĩa, chỉ để buộc một sự chuyển đổi nhẹ
Nếu chạy trên giả lập, sự di cư mất vài giây, cơ sở dữ liệu tăng gấp đôi về kích thước và cùng một truy vấn bây giờ mất ít hơn một giây để trở về thay vì phút.
Điều này sẽ giải quyết được vấn đề của tôi, buộc phải di chuyển, nhưng việc di chuyển đó mất 3 phút trên iPad và xảy ra ở nền trước.
Vì vậy, mũ của tôi đang ở ngay bây giờ, giải pháp tốt nhất cho tôi sẽ vẫn là để ngăn chặn các chỉ mục được loại bỏ, bất kỳ giải pháp nhập khẩu khác lúc khởi động chỉ mất quá nhiều thời gian.
Hãy cho tôi biết nếu bạn cần thêm làm rõ ...

Cập nhật 2
Vì vậy, kết quả tốt nhất mà tôi đã có cho đến nay là để gieo rắc các cơ sở dữ liệu dữ liệu cốt lõi với các tập tin SQLite được sản xuất từ ​​một công cụ nhanh chóng với tương tự mô hình dữ liệu, nhưng không có các chỉ mục được thiết lập khi tạo tệp sqlite. Sau đó, tôi nhập tệp sqlite này vào ứng dụng dữ liệu lõi với các chỉ mục được đặt và cho phép di chuyển nhẹ. Đối với 2 triệu bản ghi trên iPad mới, thời gian di chuyển này mất 3 phút. Ứng dụng cuối cùng phải có gấp 5 lần số lượng hồ sơ này, vì vậy chúng tôi vẫn đang xem xét thời gian xử lý dài. Nếu tôi đi tuyến đường đó, câu hỏi mới sẽ là: có thể thực hiện di chuyển nhẹ trong nền không?

Cập nhật
Câu hỏi của tôi là không làm thế nào để tạo ra một công cụ để cư một cơ sở dữ liệu Core Data, và sau đó nhập tệp sqlite vào ứng dụng của tôi.
Tôi biết làm thế nào để làm điều này, tôi đã làm nó vô số lần.
Nhưng cho đến bây giờ, tôi đã không nhận ra rằng phương pháp như vậy có thể có một số tác dụng phụ: trong trường hợp của tôi, một thuộc tính được lập chỉ mục trong cơ sở dữ liệu kết quả rõ ràng bị 'không lập chỉ mục' khi nhập tệp sqlite theo cách đó.
Nếu bạn có thể xác minh rằng bất kỳ dữ liệu được lập chỉ mục nào vẫn được lập chỉ mục sau khi chuyển, tôi quan tâm để biết cách bạn tiến hành hoặc chiến lược nào tốt nhất để tạo cơ sở dữ liệu hiệu quả như vậy.

gốc

Tôi có một tập tin CSV lớn (hàng triệu dòng) với 4 cột, dây và phao nổi. Tính năng này dành cho ứng dụng iOS.

Tôi cần dữ liệu này được tải vào dữ liệu cốt lõi trong lần đầu tiên ứng dụng được tải.

Ứng dụng này không hoạt động nhiều cho đến khi dữ liệu có sẵn, do đó tải thời gian quan trọng, vì người dùng lần đầu rõ ràng không muốn ứng dụng mất 20 phút để tải trước khi có thể chạy.

Hiện tại, mã hiện tại của tôi mất 20 phút trên iPad mới để xử lý tệp csv 2 triệu dòng.

Tôi đang sử dụng ngữ cảnh nền để không khóa giao diện người dùng và lưu ngữ cảnh mỗi 1.000 bản ghi

Ý tưởng đầu tiên là tạo cơ sở dữ liệu trên trình mô phỏng, sau đó sao chép/dán nó vào thư mục tài liệu lần đầu tiên khởi động, vì đây là cách phổ biến không chính thức của việc tạo một cơ sở dữ liệu lớn. Thật không may, các chỉ mục dường như không tồn tại như một sự chuyển giao, và mặc dù cơ sở dữ liệu đã có sẵn chỉ sau vài giây, hiệu suất là khủng khiếp vì các chỉ mục của tôi đã bị mất. Tôi đã đăng một câu hỏi về các chỉ mục đã có, nhưng dường như không có câu trả lời tốt cho điều đó.

Vì vậy, những gì tôi đang tìm kiếm, hoặc là:

  • một cách để cải thiện hiệu suất trên tải hàng triệu bản ghi trong dữ liệu cốt lõi
  • nếu cơ sở dữ liệu được nạp sẵn và di chuyển lúc khởi động đầu tiên, một cách để giữ các chỉ mục của tôi
  • thực tiễn tốt nhất để xử lý loại kịch bản này.Tôi không nhớ sử dụng bất kỳ ứng dụng nào yêu cầu tôi đợi x phút trước khi sử dụng lần đầu (nhưng có thể The Daily, và đó là một trải nghiệm khủng khiếp).
  • Bất kỳ cách sáng tạo nào để người dùng chờ đợi mà không nhận ra điều đó: nhập vào nền trong khi thực hiện hướng dẫn, v.v ...
  • Không sử dụng dữ liệu lõi?
  • ...
+0

Vậy làm cách nào bạn kết thúc "dọn dẹp" dự án để nó hoạt động chính xác? – lnafziger

+0

Làm sạch không hoạt động, nhưng khởi động lại máy tính xách tay, thủ công làm sạch tất cả các tham chiếu đến tập tin, vv, dường như đã 'giải quyết' vấn đề. lạ ... mặc dù tôi cũng đã phải loại bỏ các dòng di chuyển nhẹ để buộc không di chuyển (vì điều này sẽ mất nhiều phút). Nhìn chung, đây không phải là việc thực hiện sạch sẽ tôi hy vọng, nhưng điều này hoạt động ... cho đến khi một phiên bản 2 cần nâng cấp mô hình dữ liệu, sau đó tôi gặp rắc rối –

Trả lời

6

Pre-tạo ra cơ sở dữ liệu bằng cách sử dụng một ứng dụng ẩn (nói, một tiện ích dòng lệnh) viết bằng Cocoa, chạy trên OS X, và sử dụng cùng một khuôn khổ Core Data rằng iOS sử dụng . Bạn không cần phải lo lắng về "chỉ mục còn sống sót" hoặc bất kỳ thứ gì - đầu ra là tệp cơ sở dữ liệu .sqlite được tạo bởi Dữ liệu cốt lõi, trực tiếp và ngay lập tức có thể sử dụng được bằng ứng dụng iOS.

Miễn là bạn có thể làm thế hệ DB ngoại tuyến, đó là giải pháp tốt nhất cho đến nay. Tôi đã sử dụng thành công kỹ thuật này cho các cơ sở dữ liệu được tạo sẵn để triển khai iOS. Kiểm tra câu hỏi/câu trả lời trước của tôi để biết thêm chi tiết.

+0

Tôi cũng đã làm điều tương tự mà không có vấn đề về chỉ mục ... – lnafziger

+0

Ý của bạn là gì, tôi không cần phải lo lắng về các chỉ mục của mình; như tôi đã nói trong câu hỏi của mình, tôi đã thực hiện phương pháp chính xác này, đầu ra là tệp cơ sở dữ liệu sqlite (200Mb) và khi được sử dụng trong ứng dụng của tôi với cùng một mô hình, tệp đã giảm xuống 110Mb và hiệu suất rõ ràng cho thấy rằng các chỉ mục của tôi không đang làm việc. Vì vậy, tôi lo lắng về các chỉ mục của tôi, đây là toàn bộ vấn đề! –

+0

@nafziger, bạn có nghĩa là bạn đã lập chỉ mục trong mô hình dữ liệu cốt lõi của mình và bạn biết chắc chắn rằng các chỉ mục đó vẫn hoạt động khi chúng nên sử dụng lại tệp sqlite đó? Nếu vậy, phương pháp luận của bạn là gì để đảm bảo các chỉ mục của bạn vẫn hoạt động? –

0

Tôi chỉ mới bắt đầu với SQLite và tôi cần tích hợp một DB vào một trong các ứng dụng của tôi sẽ có nhiều dữ liệu được lập chỉ mục trong cơ sở dữ liệu SQLite. Tôi đã hy vọng tôi có thể làm một số phương pháp mà tôi có thể chèn số lượng lớn thông tin của tôi vào một tệp SQLite và thêm tệp đó vào dự án của tôi. Sau khi khám phá và đọc qua câu hỏi của bạn, câu trả lời được cung cấp và nhiều nhận xét, tôi quyết định kiểm tra nguồn SQLite để xem liệu tôi có thể tạo ra đầu hoặc đuôi của vấn đề này hay không.

Suy nghĩ ban đầu của tôi là việc triển khai thực hiện SQLite trên iOS thực tế là loại bỏ các chỉ mục của bạn. Lý do là vì ban đầu bạn tạo chỉ mục DB của mình trên hệ thống x86/x64. IOS là bộ xử lý ARM và các số được xử lý khác nhau. Nếu bạn muốn các chỉ mục của bạn được nhanh chóng, bạn nên tạo ra chúng theo cách mà chúng được tối ưu hóa cho bộ xử lý mà chúng sẽ được tìm kiếm.

Vì SQLite dành cho nhiều nền tảng, nên nó sẽ tạo ra từ khi thả bất kỳ chỉ mục nào đã được tạo trong kiến ​​trúc khác và xây dựng lại chúng. Tuy nhiên, vì không ai muốn chờ một chỉ mục để xây dựng lại lần đầu tiên nó được truy cập, các nhà phát triển SQLite có nhiều khả năng quyết định chỉ thả chỉ mục.

Sau khi tìm hiểu mã SQLite, tôi đã đi đến kết luận rằng đây là số nhiều khả năng xảy ra nhất. Nếu không vì lý do kiến ​​trúc bộ xử lý, tôi đã tìm thấy mã (xem analyze.c và các thông tin meta khác trong sqliteint.h) trong đó các chỉ mục bị xóa nếu chúng được tạo trong ngữ cảnh không mong muốn. Linh cảm của tôi là bối cảnh thúc đẩy quá trình này là cách cấu trúc dữ liệu b-tree cơ bản được xây dựng cho khóa hiện có. Nếu cá thể hiện tại của SQLite không thể tiêu thụ khóa, nó sẽ xóa nó.

Điều đáng nói đến là Trình mô phỏng iOS chỉ là-- trình giả lập. Nó không phải là một trình giả lập của phần cứng. Như vậy, ứng dụng của bạn đang chạy trên thiết bị giả iOS, chạy trên bộ xử lý x86/x64.

Khi ứng dụng của bạn và DB SQLite được tải xuống thiết bị iOS của bạn, một biến thể được biên dịch ARM được tải, cũng liên kết tới các thư viện được biên dịch ARM trong iOS. Tôi không thể tìm thấy mã ARM cụ thể liên kết với SQLite, vì vậy tôi tưởng tượng Apple đã phải sửa đổi nó cho phù hợp với họ. Cũng có thể là một phần của vấn đề. Đây có thể không phải là vấn đề với mã root-SQLite, nó có thể là vấn đề với biến thể được biên dịch của Apple/ARM.

Giải pháp hợp lý duy nhất mà tôi có thể đưa ra là bạn có thể tạo ứng dụng trình phát mà bạn chạy trên máy iOS của mình. Chạy ứng dụng, xây dựng các khóa và sau đó tách tệp SQLite khỏi thiết bị. Tôi tưởng tượng một tập tin như vậy sẽ làm việc trên tất cả các thiết bị, vì tất cả các bộ vi xử lý ARM được sử dụng bởi iOS là 32-bit.

Một lần nữa, câu trả lời này là một chút của một dự đoán được giáo dục. Tôi sẽ gắn thẻ lại câu hỏi của bạn dưới dạng SQLite. Hy vọng rằng một guru có thể tìm thấy điều này và có thể cân nhắc về vấn đề này. Tôi thực sự muốn biết sự thật vì lợi ích của riêng tôi.

Các vấn đề liên quan