5

Tôi có một số tính không hiệu quả trong ứng dụng mà tôi muốn hiểu và khắc phục.Mẫu dữ liệu cốt lõi: cách cập nhật hiệu quả thông tin cục bộ với các thay đổi từ mạng?

thuật toán của tôi là:

fetch object collection from network 
for each object: 
    if (corresponding locally stored object not found): -- A 
    create object 
    if (a nested related object locally not found): -- B 
     create a related object 

Tôi đang làm việc kiểm tra trên dây chuyền A và B bằng cách tạo ra một truy vấn ngữ với chính các đối tượng có liên quan của đó là một phần của giản đồ của tôi. Tôi thấy rằng cả hai A (luôn luôn) và B (nếu thực hiện phân nhánh thành phần đó) tạo ra một SQL chọn như:

2010-02-05 01:57:51.092 app[393:207] CoreData: sql: SELECT <a bunch of fields> FROM ZTABLE1 t0 WHERE t0.ZID = ? 
2010-02-05 01:57:51.097 app[393:207] CoreData: annotation: sql connection fetch time: 0.0046s 
2010-02-05 01:57:51.100 app[393:207] CoreData: annotation: total fetch execution time: 0.0074s for 0 rows. 
2010-02-05 01:57:51.125 app[393:207] CoreData: sql: SELECT <a bunch of fields> FROM ZTABLE2 t0 WHERE t0.ZID = ? 
2010-02-05 01:57:51.129 app[393:207] CoreData: annotation: sql connection fetch time: 0.0040s 
2010-02-05 01:57:51.132 app[393:207] CoreData: annotation: total fetch execution time: 0.0071s for 0 rows. 

0.0071s cho một truy vấn là tốt trên một thiết bị 3GS, nhưng nếu bạn thêm 100 trong số này lên, bạn chỉ có một bộ chặn 700ms.

Trong mã của tôi, tôi đang sử dụng một helper để làm những fetches:

- (MyObject *) myObjectById:(NSNumber *)myObjectId { 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    [fetchRequest setEntity:[self objectEntity]]; // my entity cache  
    [fetchRequest setPredicate:[self objectPredicateById:objectId]]; // predicate cache  
    NSError *error = nil; 
    NSArray *fetchedObjects = [moc executeFetchRequest:fetchRequest error:&error]; 
    if ([fetchedObjects count] == 1) { 
     [fetchRequest release]; 
     return [fetchedObjects objectAtIndex:0]; 
    } 
    [fetchRequest release]; 
    return nil; 
} 

MyObject *obj = [self myObjectById]; 
if (!obj) { 
    // [NSEntityDescription insertNewObjectForEntityForName: ... etc 
} 

tôi cảm thấy điều này là sai và tôi nên làm việc kiểm tra một số cách khác. Nó chỉ nên nhấn cơ sở dữ liệu một lần và nên đến từ bộ nhớ sau đó, phải không? (SQL được thực thi ngay cả đối với các đối tượng mà tôi biết chắc chắn tồn tại cục bộ và nên được nạp vào bộ nhớ với các truy vấn trước đó.) Nhưng, nếu tôi chỉ có myObjectId từ một nguồn bên ngoài, thì đây là điều tốt nhất tôi có thể nghĩ đến. Vì vậy, có lẽ câu hỏi là: nếu tôi có myObjectId (thuộc tính int64 dữ liệu lõi trên MyObject), tôi nên kiểm tra chính xác xem đối tượng địa phương có liên quan có tồn tại trong kho lưu trữ CD hay không? Không. Tải trước toàn bộ tập hợp các kết quả phù hợp và sau đó dự đoán một mảng cục bộ?

(Một giải pháp có thể là di chuyển điều này đến chuỗi nền. Điều này sẽ ổn, ngoại trừ khi tôi nhận được các thay đổi từ chuỗi và làm [moc mergeChangesFromContextDidSaveNotification: aNotification]; (nhận các đối tượng đã thay đổi từ chủ đề nền bằng cách thông báo), thao tác này vẫn bị chặn.)

Trả lời

9

Đọc "Triển khai Tìm hoặc Tạo hiệu quả" trong Hướng dẫn lập trình dữ liệu cốt lõi.

Về cơ bản, bạn cần phải tạo một mảng các ID hoặc thuộc tính như tên hoặc bất kỳ thứ gì bạn có từ thực thể đối tượng được quản lý.

Sau đó, bạn cần phải tạo một vị từ sẽ lọc các đối tượng được quản lý bằng mảng này.

[fetchRequest setPredicate:[NSPredicate predicateWithFormat: @"(objectID IN %@)", objectIDs]]; 

Tất nhiên "objectID" có thể là bất kỳ thứ gì bạn có thể sử dụng để nhận dạng. Nó không phải là NSManagedObjectID.

Sau đó, bạn có thể thực hiện một yêu cầu tìm nạp và lặp lại các đối tượng đã tìm nạp, để tìm các bản sao. Thêm mới nếu nó không tồn tại.

+0

Liên kết? Tôi đã đọc Hướng dẫn lập trình dữ liệu cốt lõi tại http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html, nhưng tôi không nhớ bất cứ điều gì về Tìm-hoặc-Tạo ở đó . – Jaanus

+6

Đây là liên kết http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html#//apple_ref/doc/uid/TP40003174 –

+1

Tôi đã đánh dấu câu trả lời này là câu trả lời vì nó mang ý tưởng tương tự như một số ý tưởng khác (bộ nhớ danh tính có liên quan đến bộ nhớ cache), nhưng có thêm tiền thưởng liên kết đến tài liệu chính thức. Tìm-hoặc-Tạo là chính xác những gì này là về./Đối với bản thân tôi, vì dữ liệu của tôi nhỏ, tôi kết thúc việc tìm nạp toàn bộ đối tượng được đặt vào bộ nhớ, vì dữ liệu đủ nhỏ và tôi cần truy cập vào nó, và cách lưu trữ này cực nhanh. – Jaanus

3

Có thể bạn có thể học một bài học từ ứng dụng email.

Chúng hoạt động bằng cách truy vấn đầu tiên máy chủ để biết danh sách ID thư. Khi khách hàng có danh sách đó, nó sẽ so sánh với danh sách lưu trữ dữ liệu cục bộ của nó để xem liệu có gì khác không.

Nếu có sự khác biệt, có một trong hai hành động. 1. Nếu nó tồn tại trên máy khách, nhưng không phải máy chủ VÀ chúng tôi là IMAP, sau đó xóa cục bộ. 2. Nếu nó tồn tại trên máy chủ, nhưng không tồn tại trên máy khách, hãy tải xuống phần còn lại của tin nhắn.

Trong trường hợp của bạn, truy vấn đầu tiên cho tất cả các id. Sau đó gửi truy vấn theo dõi để lấy tất cả dữ liệu cho những dữ liệu bạn chưa có.

Nếu bạn có trường hợp bản ghi có thể tồn tại cục bộ, nhưng có thể đã được cập nhật kể từ lần tải xuống cuối cùng trên máy chủ, thì truy vấn của bạn nên bao gồm ngày cập nhật cuối cùng.

+0

Truy vấn máy chủ giá rẻ cho tôi và thực hiện đồng bộ. Vấn đề của tôi là phần "truy vấn cho tất cả các ID cục bộ" là không hiệu quả và/hoặc tôi không thể tìm ra cách thực hiện nó một cách chính xác. – Jaanus

1

Có vẻ như những gì bạn cần là một NSSet của NSManagedObjectID được tải vào bộ nhớ hoặc được lưu trữ ở nơi nào đó được truy cập nhanh hơn lưu trữ đối tượng liên tục của bạn.

Bằng cách đó bạn có thể so sánh ID đối tượng từ mạng với ID đối tượng từ bộ nhớ cache mà không phải thực hiện yêu cầu tìm nạp trên tập dữ liệu lớn.

Có thể thêm ID vào bộ nhớ cache từ bên trong -awakeFromInsert trong các lớp thực thể được quản lý của bạn?

+0

Các đối tượng từ mạng có một "ID" khác nhau của NSNumber không liên quan đến NSManagedObjectID. Đây là thuộc tính mà tôi đang sử dụng trong ví dụ. Vì vậy, chỉ NSSet của NSManagedObjectID-s là không đủ, vì tôi không có "ID bên ngoài-> managedId" lập bản đồ. – Jaanus

3

Bạn nên thực hiện một lần tìm nạp trên tất cả các đối tượng, nhưng chỉ tìm nạp ID máy chủ cho các đối tượng.

Sử dụng setPropertiesToFetch: với setResultType: đặt thành NSDictionaryResultType.

1

Sau khi chiến đấu với cùng một vấn đề này cho các lứa tuổi, cuối cùng tôi đã tình cờ gặp phải mục nhập blog này hoàn toàn giải quyết nó (và là một khối mã có thể tái sử dụng làm tiền thưởng!).

http://henrik.nyh.se/2007/01/importing-legacy-data-into-core-data-with-the-find-or-create-or-delete-pattern

Khi mẫu mã không bao gồm phần mạng; bạn chỉ cần tải nó vào một NSDictionary. và sau đó điều này đề cập đến việc đồng bộ hóa bối cảnh dữ liệu cốt lõi cục bộ.

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