2011-11-19 63 views
9

我正在研究一個iOS閃存卡風格的學習應用程序,它在加載時需要從Core Data獲取一堆數據。但是,我需要的數據是實體的一個相當特定的子集,基於用戶設置,所以有多個謂詞涉及測試等價性。我發現這些提取速度非常慢,基於對SQLite的研究,我認爲索引在這裏是一個不錯的選擇。使用核心數據時可能存在複雜索引嗎?

現在,我明白(主要是從閱讀其他stackoverflow問題)SQLite和核心數據是兩個不同的,基本上正交的東西,不應該混淆。但我的理解是,你應該通過Core Data來完成任何類型的數據庫工作和調整;在應用中優化或設計對象永久性時,您不應該嘗試繞過並直接與SQLite合作。

但我唯一可以找到的核心數據中的索引是一個「索引」複選框模型中的每個屬性。這只是沒有做我想要的那種優化。

這裏的讀取請求,目前:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"SKUserItem" inManagedObjectContext:context]; 
fetchRequest.entity = entity; 

NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"next" ascending:YES] autorelease]; 
fetchRequest.sortDescriptors = [NSArray arrayWithObject:sortDescriptor]; 

NSMutableArray *predicates = [NSMutableArray arrayWithCapacity:6]; 
[predicates addObject:[NSPredicate predicateWithFormat:@"next < %f", now() + (60.0*60.0*24.0)]]; 
[predicates addObject:[NSPredicate predicateWithFormat:@"next > %f", nextOffset]]; 
[predicates addObject:[NSPredicate predicateWithFormat:@"user == %@", user]]; 
[predicates addObject:[NSPredicate predicateWithFormat:@"langRaw == %d", lang]]; 

NSArray *stylePredicates = [NSArray arrayWithObjects:[NSPredicate predicateWithFormat:@"styleRaw == %d", SK_SIMP_AND_TRAD], [NSPredicate predicateWithFormat:@"styleRaw == %d", self.style], nil]; 
[predicates addObject:[NSCompoundPredicate orPredicateWithSubpredicates:stylePredicates]]; 

if([self.parts count] == 4 || (self.lang == SK_JA && [self.parts count] == 3)) 
    ; // don't have to filter by parts; they're studying all of them 
else { 
    NSMutableArray *partPredicates = [NSMutableArray arrayWithCapacity:[self.parts count]]; 
    for(NSString *part in self.parts) 
     [partPredicates addObject:[NSPredicate predicateWithFormat:@"partRaw == %d", partCode(part)]]; 
    [predicates addObject:[NSCompoundPredicate orPredicateWithSubpredicates:partPredicates]]; 
} 

NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates]; 
fetchRequest.predicate = compoundPredicate; 

所以基本上這是什麼取確實是有點明年(當給定項目到期時間)和用戶名過濾,語言正在研究,風格之中學習(中文簡體和傳統)和正在研究的部分(寫作,語調,閱讀或定義),並且只在「下一個」範圍內進行。下面是我從調整和擺弄中學到的東西的簡短列表:

  1. 它總是掃描整個表格,或者似乎是。雖然下一個索引,即使我強迫它搜索範圍,我知道將不會返回任何內容,它仍然需要幾秒鐘才能完成獲取。
  2. 謂詞謂詞,任何數量的謂詞都會使這個變慢。如果我刪除了一些,但不是全部,它是一樣慢。如果我刪除所有謂詞(從而打破應用程序),那麼速度會更快。
  3. 速度在很大程度上取決於表中總共有多少個UserItems。有更多的項目,這是更慢。有些人可能擁有數以萬計的項目,那麼這個獲取可能需要10秒才能完成。這導致了我的應用程序暫停尷尬。
  4. 下一個值的上限並不是因爲我們需要它,而是因爲它加快了取回的速度。
  5. 讓查詢返回字典中的屬性子集(而不是整個託管對象)並且懶懶地提取其餘部分的速度會更快,但仍然不夠快。

我來自Google App Engine這裏,所以我習慣了他們在那裏提供的索引。基本上我想要這種索引,但通過核心數據應用於SQLite。我發現有關在SQLite中添加索引的信息,我會希望的,但通過核心數據做這種索引,我找不到任何信息。

+0

我還沒有遇到核心數據,顯示了1個謂詞性能問題,但如果你只談論項目數以萬計,你可能使用非基於SQL的核心數據存儲找到更好的性能。例如,二進制存儲類型可能會更快。 –

+0

感謝您的建議。我試了一下,但在我的3GS上測試顯示,二進制存儲類型無法處理那麼多的數據。在程序因使用太多內存而崩潰之前,我加載了一個擁有30,000個以上項目的帳戶。可能是因爲SKUserItem實體中有26個屬性。 –

+0

啊,那太糟糕了。我真的不明白爲什麼第一點是屬於索引的情況。 –

回答

18

想要的是Compound Data Core Data在iOS 5.0及更高版本中支持的內容。

您可以在Xcode中設置它:該實體檢查有指數部分,或者如果你在代碼中創建的NSEntityDescription,使用-setCompoundIndexes:

如果你使用Xcode中,你會在索引添加一行節說

next,user,langRaw 

這樣,SQL可以使用索引來進行查詢。

2

核心數據有一個SQL後端。你做這件事的方式是將一個表中的所有數據(一個實體的一部分)都存放起來,並且如你所說正在發生的事情,要找到你正在查找的對象將需要搜索所有行。

在您的數據模型中,您需要將您正在搜索的一些屬性分解爲其他實體。試着讓它更基於對象,並考慮你將要搜索的內容。

例如 有一個用戶,語言的實體,也可能是一個用於課程或任何基於時間的事物,它是你正在搜索。

的課實體有一個爲語言和用戶的單一關係一對多的關係。 (或很多,如果多個用戶需要的類)

然後尋找一個用戶的數據讀取你該用戶並調查她的語言與教訓屬性來了解更多信息。

要查找用戶學習一門語言獲取您正在尋找的語言實體並調查用戶財產清單。

+0

我不認爲人際關係能解決這個問題,除非我不瞭解他們的能力。他們不是我正在學習的課程,它更像是一大堆閃存卡。讓我們簡化它;說我只想爲鮑勃的中國卡,到現在爲止。但是也有日本的鮑勃卡。丹的中國名片。每個人都有成千上萬的人,他們的「下一個」(到期)價值都混雜在一起。如果我得到了所有與鮑勃有關的卡片,我會爲他們提供中文和日文版本。或者如果我得到所有與中國人有關的卡片,我會得到丹和鮑勃的。對?那麼他們將如何被下一個排序/綁定? –