2012-07-05 23 views
13

Tôi đang tìm một cách hiệu quả để lưu trữ và tìm kiếm UUID trong Dữ liệu chính. UUID đó được tạo ra bởi nhiều thiết bị iOS trong một hệ thống phân tán. Mỗi thiết bị có thể lưu trữ khoảng 20-50k UUID.Cách chèn và tìm nạp hiệu quả UUID trong Dữ liệu chính

Rõ ràng là việc lưu trữ UUID dưới dạng Chuỗi trong dữ liệu chính sẽ làm tổn hại đến hiệu quả lập chỉ mục trên đó. Nhưng sau một loạt các nghiên cứu tôi thấy rằng lưu trữ UUID như dữ liệu nhị phân trong dữ liệu lõi (và chỉ số nó) có thể kém hiệu quả hơn so với lưu trữ nó như là chuỗi.

Vì không có kiểu dữ liệu giống như BINARY hoặc VARBINARY trong SQLit được hỗ trợ. Tôi đoán rằng bất kỳ loại dữ liệu nhị phân nào trong dữ liệu lõi được lưu trữ dưới dạng BLOB trong SQLit. Vì BLOB có thể là loại dữ liệu chậm nhất để được lập chỉ mục, nó sẽ gây ảnh hưởng xấu đến hiệu suất.

Vì vậy, bất kỳ ai cũng có thể trả lời, có cách nào hiệu quả hơn để lưu trữ UUID trong Dữ liệu chính không?

+0

bạn nhận thức được rằng quyền truy cập vào UDID của đã bị phản đối như của iOS 5, đúng không? –

+3

OP nói về UUID khác với UDID. –

+0

@JodyHagins, bạn nói đúng. UUID tôi đã đề cập là ID duy nhất phổ biến cho ManagedObject được tạo bởi ứng dụng của tôi. –

Trả lời

30

Lưu trữ chúng dưới dạng chuỗi ASCII và đặt trường thành chỉ mục.

EDIT

Egads, tôi tình cờ được làm một số poking về, và tình cờ gặp này. Thật là một câu trả lời đáng xấu hổ. Tôi phải có một chút tâm trạng ngày hôm đó. Nếu có thể, tôi chỉ xóa nó và tiếp tục. Tuy nhiên, điều đó là không thể, vì vậy tôi sẽ cung cấp một bản cập nhật.

Đầu tiên, cách duy nhất để biết "hiệu quả" là đo lường, xem xét thời gian và không gian chương trình cũng như nỗ lực lập trình và phức tạp của mã nguồn.

May mắn thay, điều này khá dễ dàng.

Tôi đã viết một ứng dụng OSX rất đơn giản. Mô hình bao gồm một thuộc tính duy nhất: identifier.

Không có vấn đề gì trong số này, nếu bạn không đánh dấu thuộc tính của mình là chỉ mục. Nó sẽ mất nhiều thời gian hơn nhiều khi tạo cửa hàng, nhưng nó sẽ làm cho các truy vấn nhanh hơn nhiều.

Ngoài ra, lưu ý rằng việc tạo một vị cho một thuộc tính nhị phân là chính xác giống như tạo ra một cho một chuỗi:

fetchRequest.predicate = 
    [NSPredicate predicateWithFormat:@"identifier == %@", identifier]; 

Ứng dụng này rất đơn giản. Đầu tiên, nó tạo N đối tượng và gán UUID cho thuộc tính định danh. Nó lưu MOC mỗi 500 đối tượng. Sau đó, chúng tôi lưu trữ tất cả số nhận dạng vào một mảng và ngẫu nhiên trộn chúng. Toàn bộ ngăn xếp CD sau đó bị rách hoàn toàn để loại bỏ tất cả khỏi bộ nhớ.

Tiếp theo, chúng tôi tạo lại ngăn xếp và sau đó lặp lại các số nhận dạng và thực hiện tìm nạp đơn giản. Đối tượng fetch được xây dựng, với một vị từ đơn giản để tìm nạp một đối tượng đó. Tất cả điều này được thực hiện bên trong một autoreleasepool để giữ cho mỗi lấy càng nguyên sơ càng tốt (tôi thừa nhận rằng sẽ có một số tương tác với bộ đệm CD). Điều đó không quan trọng lắm, vì chúng tôi chỉ so sánh các kỹ thuật khác nhau.

Mã định danh nhị phân là 16 byte cho UUID.

Chuỗi UUID là chuỗi 36 byte, kết quả của việc gọi [uuid UUIDString] và trông giống như thế này (B85E91F3-4A0A-4ABB-A049-83B2A8E6085E).

Chuỗi Base64 là chuỗi 24 byte, kết quả của cơ sở 64 mã hóa dữ liệu nhị phân UUID 16 byte và trông giống như thế này (uF6R80oKSrugSYOyqOYIXg ==) cho cùng UUID.

Đếm là số đối tượng cho lần chạy đó.

Kích thước SQLite là kích thước của tệp sqlite thực tế.

kích thước WAL là lớn như thế nào WAL (write-trước-logging) tập tin được - chỉ cần FYI ...

Tạo là số giây để tạo ra cơ sở dữ liệu, bao gồm tiết kiệm.

Truy vấn là số giây để truy vấn từng đối tượng.

Data Type  | Count (N) | SQLite Size | WAL Size | Create | Query 
--------------+-----------+-------------+-----------+---------+--------- 
Binary  | 100,000 | 5,758,976 | 5,055,272 | 2.6013 | 9.2669 
Binary  | 1,000,000 | 58,003,456 | 4,783,352 | 59.0179 | 96.1862 
UUID String | 100,000 | 10,481,664 | 4,148,872 | 3.6233 | 9.9160 
UUID String | 1,000,000 | 104,947,712 | 5,792,752 | 68.5746 | 93.7264 
Base64 String | 100,000 | 7,741,440 | 5,603,232 | 3.0207 | 9.2446 
Base64 String | 1,000,000 | 77,848,576 | 4,931,672 | 63.4510 | 94.5147 

Điều đầu tiên cần lưu ý ở đây là kích thước cơ sở dữ liệu thực tế lớn hơn nhiều byte được lưu trữ (1.600.000 và 16.000.000) - được mong đợi cho cơ sở dữ liệu. Số lượng dung lượng lưu trữ bổ sung sẽ có phần tương đối so với kích thước của các đối tượng thực tế của bạn ... cái này chỉ lưu trữ số nhận dạng để phần trăm chi phí trên cao hơn). Thứ hai, về các vấn đề tốc độ, để tham khảo, thực hiện cùng 1.000.000 truy vấn đối tượng, nhưng sử dụng id đối tượng trong tìm nạp mất khoảng 82 giây (lưu ý sự khác biệt rõ rệt giữa điều đó và gọi số existingObjectWithID:error:, mất 0.3065 giây).

Bạn nên lập hồ sơ cơ sở dữ liệu của riêng mình, bao gồm việc sử dụng các công cụ thận trọng trên mã đang chạy. Tôi tưởng tượng các con số sẽ hơi khác nếu tôi thực hiện nhiều lần chạy, nhưng chúng quá gần đến mức không cần thiết cho phân tích này.

Tuy nhiên, dựa trên những con số này, hãy xem xét các phép đo hiệu quả để thực thi mã.

  • Như dự kiến, lưu trữ dữ liệu nhị phân UUID thô hiệu quả hơn về mặt không gian.
  • Thời gian tạo khá gần (sự khác biệt xuất hiện dựa trên thời gian tạo chuỗi và yêu cầu dung lượng lưu trữ bổ sung).
  • Thời gian truy vấn dường như gần như giống hệt nhau, với chuỗi nhị phân xuất hiện chậm hơn một chút. Tôi nghĩ rằng đây là mối quan tâm ban đầu - thực hiện một truy vấn trên một thuộc tính nhị phân.

Không gian giành chiến thắng nhị phân nhiều và có thể được coi là điểm đến gần cả thời gian tạo và thời gian truy vấn. Nếu chúng ta chỉ xem xét, lưu trữ dữ liệu nhị phân là người chiến thắng rõ ràng.

Thời gian lập trình và độ phức tạp của mã nguồn như thế nào?

Vâng, nếu bạn đang sử dụng phiên bản iOS và OSX hiện đại, hầu như không có sự khác biệt, đặc biệt là với một danh mục đơn giản trên NSUUID.

Tuy nhiên, có một cân nhắc cho bạn và điều đó dễ sử dụng dữ liệu trong cơ sở dữ liệu. Khi bạn lưu trữ dữ liệu nhị phân, thật khó để có được hình ảnh tốt trên dữ liệu. Vì vậy, nếu vì một lý do nào đó, bạn muốn dữ liệu trong cơ sở dữ liệu được lưu trữ một cách hiệu quả hơn cho con người, sau đó lưu trữ nó như một chuỗi là một lựa chọn tốt hơn. Vì vậy, bạn có thể muốn xem xét một mã hóa base64 (hoặc một số mã hóa khác - mặc dù hãy nhớ nó đã có trong cơ sở-256-mã hóa).

FWIW, đây là một loại ví dụ để cung cấp truy cập dễ dàng hơn để các UUID như cả NSData và base64 chuỗi:

- (NSData*)data 
{ 
    uuid_t rawuuid; 
    [self getUUIDBytes:rawuuid]; 
    return [NSData dataWithBytes:rawuuid length:sizeof(rawuuid)]; 
} 

- (NSString*)base64String 
{ 
    uuid_t rawuuid; 
    [self getUUIDBytes:rawuuid]; 
    NSData *data = [NSData dataWithBytesNoCopy:rawuuid length:sizeof(rawuuid) freeWhenDone:NO]; 
    return [data base64EncodedStringWithOptions:0]; 
} 

- (instancetype)initWithBase64String:(NSString*)string 
{ 
    NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0]; 
    if (data.length == sizeof(uuid_t)) { 
     return [self initWithUUIDBytes:data.bytes]; 
    } 
    return self = nil; 
} 

- (instancetype)initWithString:(NSString *)string 
{ 
    if ((self = [self initWithUUIDString:string]) == nil) { 
     self = [self initWithBase64String:string]; 
    } 
    return self; 
} 
+0

Lời khuyên tốt, cảm ơn. Nó có thể tiết kiệm một nửa nỗ lực cho Core Data. Nhưng tôi vẫn tự hỏi làm thế nào ASCII chuỗi được ánh xạ từ Core dữ liệu để SQLit. Tôi đoán chỉ chạy một thử nghiệm thực sự có thể nói. –

+0

Nói chung, bạn muốn đảm bảo mọi chuỗi bạn tìm kiếm được chuẩn hóa để loại trừ unicode. Ngoài ra, thay vì sử dụng các tìm kiếm phân biệt chữ hoa chữ thường, hãy chuẩn hóa dữ liệu để loại bỏ unicode và case. Sử dụng < and > thay vì BEGINSWITH, v.v. Có các đề xuất tuyệt vời trong các video WWDC 2010, 2011 và 2012. Tôi rất khuyên họ. –

+0

hi @JodyHagins Bạn có thể chỉ định tên của các video WWDC về chủ đề này không. Có quá nhiều người trong số họ. Cảm ơn trước. –

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