2014-03-05 63 views
7

在我們的一個應用程序中,我被要求記錄圖像的最後修改日期。這樣我可以檢查服務器,如果某個圖像已更改並相應地更新我的緩存。訪問文件屬性vs訪問sqlite記錄

我的第一種方法是訪問文件屬性並進行比較,但在線上的一些地方提到了延遲方面的嚴重瓶頸。

我的第二選擇是創建一個SQLite表來管理它。 (使用fmdb

我已經決定寫一個簡單的延遲測試。在接下來的測試我訪問500種文件屬性和500個sqlite的記錄:

- (void)latencyTest 
{ 
    NSMutableArray *arrayTest1 = [[NSMutableArray alloc]init]; 
    NSMutableArray *arrayTest2 = [[NSMutableArray alloc]init]; 
    FMResultSet *results = [_database executeQuery:@"SELECT * FROM `tb_media`"]; 
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 
    [formatter setDateFormat:@"dd-MM-yyyy HH:mm:ss:SSS"]; 
    NSLog(@"Time1: %@",[formatter stringFromDate:[NSDate date]]); 
    int i=1; 
    while(i<501) 
    { 
     NSString *test = [NSString stringWithFormat:@"%@/_media/media/19/%d.jpg",_outputPath,i]; 
     NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:test error:nil]; 
     NSDate *dateX = [attributes fileModificationDate]; 
     [arrayTest1 addObject:dateX]; 
     i++; 
    } 
    NSLog(@"Time2: %@",[formatter stringFromDate:[NSDate date]]); 
    while([results next]) 
    {   
     NSDate *myDate = [NSDate dateWithTimeIntervalSince1970:[results intForColumn:@"last_update"]]; 
     [arrayTest2 addObject:myDate]; 
    } 
    NSLog(@"Time3: %@",[formatter stringFromDate:[NSDate date]]); 
} 

結果:

//iPhone 5 (Actual Device) 500 Pics 

    Files Start:     05-03-2014 09:31:20:375 
    Files End & Sqlite start: 05-03-2014 09:31:20:491 
    Sqlite end:     05-03-2014 09:31:20:507 

    Files Start:     05-03-2014 09:31:56:305 
    Files End & Sqlite start: 05-03-2014 09:31:56:421 
    Sqlite end:     05-03-2014 09:31:56:437 

    Files Start:     05-03-2014 09:32:19:053 
    Files End & Sqlite start: 05-03-2014 09:32:19:170 
    Sqlite end:     05-03-2014 09:32:19:187 

正如你所看到的結果是幾乎一樣的。 我的問題是:

  1. 我的假設是使用attributesOfItemAtPath在同一時間訪問一個文件將 需要更長的時間比SQL下。我錯過了什麼嗎?

  2. 是否真的attributesOfItemAtPath訪問文件或iOS的 文件系統保持在某種數據庫爲 方便地訪問所有的屬性?

  3. 看到上述結果後,我決定採用 attributesOfItemAtPath方法。還有什麼我不是 考慮通過sqlite?

+0

我是不是知道fileModificationDate方法,謝謝:-) –

+0

你用什麼硬件進行測試?在iOS設備中,SSD的性能將明顯優於閃存。這就是說500並不是那麼多文件,即使是嵌入式硬件。你預計這個數量是否在你的緩存範圍之內?或者你將不得不擴大到成千上萬的圖像? – ImHuntingWabbits

+0

@ImHuntingWabbits這很奇怪,SSD的執行速度比我的iPhone 5慢,但說實話,模擬器並不真的讓我感興趣,只有實際的設備。當試圖查詢超過500個文件時,我用sqlite得到了一些限制,出現「SQLite錯誤:複合SELECT中的條目過多」,所以我現在要保留500個。 – Segev

回答

5

在我討論解決方案之前,您的評估策略存在一些問題。

1)您還沒有納入NSLog和While循環所花費的時間。 75%的時間是由他們採取的 而你只是想比較intForColumn與attributesOfItemAtPath。正確的做法是運行儀器Timer Profiler並比較檢索單個記錄的時間。

2)您已經使用FMDB作爲文件管理器。內部FMDB序列化文件中的數據。 FMDB/SQL Lite的核心在於它的數據結構,特別是你根本沒有使用過的索引。 因此,即使您比較了記錄的時間,您觀察者FMDB所花費的時間也會比文件管理器多,因爲額外開銷會以特定格式序列化數據。

3)X次訪問記錄的訪問時間通過訪問完成到磁盤(硬盤驅動器)而不是堆的次數進行比較。你在做什麼是在兩種情況下數據存儲的堆訪問。所以你根本看不出有什麼不同。

這是否意味着文件管理器比FMDB更好,絕對不是! 這裏有幾個原因爲什麼:

FMDB只有當它被配置爲這樣做時才表現良好。 FMDB的核心在於分頁(緩存到堆)和索引兩個方面。 讓我一次解釋你的每一個。

1)假設您正試圖訪問100張圖像的時間戳。每個圖像有1000個時間戳。這意味着你必須使100 * 1000 = 100,000訪問數據存儲。 如果圖片很小,Filemanager會將該文件加載到堆中,並且訪問速度會比FMDB快,但是如果沒有足夠的堆空間,應用程序將發出內存警告並從磁盤訪問文件,而不是緩存,速度明顯較慢。

所以它的二進制狀態從堆全部或全部從磁盤

FMDB優於這種狀態並檢索根據可用的堆空間的部分記錄。這使得訪問速度更快時,你有一個巨大的記錄夾頭。

測試此場景的理想方法是對至少10,000張圖像(不是時間戳)運行您的futintion latencyTest。這樣,與總體時間相比,日誌時間和迭代速度可以忽略不計。

2)索引結構,這可以回溯到SQL Lite的基礎知識。您可能需要添加一個額外的屬性調用作爲訪問圖像的次數併爲其編制索引。這將大大提高執行力。 Filemeanger不太可能。

我推薦的解決方案。 1)如果數據少於2 MB(圖像加時間戳)去找Filemenager

2)如果數據大於2MB,請使用Core Data/FMDB。

核心數據具有針對多線程環境的額外性能調整以及諸如用於加密的無縫集成等更多附加功能。

0

首先,正如@ kunal所說,你的基準測試方法不確定,可能會誤導你的決定。

話雖如此,attributesOfItemAtPath:做一點點的開銷,如果你只需要修改日期和性能真的是你的問題。你可以做的是用lstat代替。這類似於你的情況(請注意,我刪除陣列,以避免對基準不需要的開銷):

#import <sys/stat.h> 

- (void)latencyTest 
{ 
    // *********************** Test 1 ***********************************// 
    double t = CACurrentMediaTime(); 
    for (NSInteger i = 1; i < 748; i++) 
    { 
     NSString *path = [NSString stringWithFormat:kMediaPath, i]; 
     NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path 
                        error:nil]; 
     NSDate *dateX = [attributes fileModificationDate]; 
    } 
    double total = CACurrentMediaTime() - t; 
    NSLog(@"Total time fileManager: %fs, average per read: %fs", total, total/747.f); 

    // *********************** Test 2 ***********************************// 
    struct stat linfo; 
    t = CACurrentMediaTime(); 
    for (NSInteger i = 1; i < 748; i++) 
    { 
     NSString *path = [NSString stringWithFormat:kMediaPath, i]; 
     lstat([path cStringUsingEncoding:NSUTF8StringEncoding], &linfo); 
     NSDate *dateX = [NSDate dateWithTimeIntervalSince1970:linfo.st_mtime]; 
    } 
    total = CACurrentMediaTime() - t; 
    NSLog(@"Total time lstat: %fs, average per read: %fs", total, total/747.f); 
} 

對於748個圖像的輸入,我的結果是:

// Simulator (iOS 7.1) 

Total time fileManager: 0.061365s, average per read: 0.000082s 
Total time lstat: 0.004313s, average per read: 0.000006s 

// iPhone 5s Device (iOS 7.1) 

Total time fileManager: 0.019299, average per read: 0.000026 
Total time lstat: 0.008520, average per read: 0.000011