2009-11-25 9 views
0

필드 날짜가있는 모델이 있습니다. 1 년 내내 모든 레코드 수를 가져 오거나 오늘 날짜에 대한 레코드가 0으로 표시되지 않으면 모든 레코드를 가져와야합니다. 이제는 모든 레코드를 1 년 동안 가져 와서 손으로 만듭니다. 핵심 데이터 쿼리를 사용하여이를 수행 할 수 있습니까?핵심 데이터 복합 쿼리

답변

1

일반적으로 코어 데이터에서 여러 페치로 나누기보다는 앞에 수행해야하는 모든 페칭을 수행하는 것이 훨씬 빠릅니다.

나는 두 가지 방법으로 그 해의 하루 기록을 계산하려고 :

  1. 이 년 동안 모든 레코드를 가져옵니다. 해당 레코드의 고유 한 날짜를 찾으십시오. 날짜를 반복하고 레코드를 계산하십시오.

  2. 일년 중 매일 반복합니다. 해당 날짜의 레코드에 대해서만 카운트 만 가져 오기를 수행하십시오.

작은 데이터베이스 (48 개 레코드)에서는 첫 번째 방법이 약 90 배 빠릅니다. 첫 번째 접근 방식의 성능은 더 많은 레코드가 추가되고 두 ​​번째 접근 방식이 거의 같아 질수록 악화 될 것이라고 생각합니다.

- (void)doFullLoadTestWithYear:(int)year { 
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Record" inManagedObjectContext:self.managedObjectContext]; 
[fetchRequest setEntity:entity]; 

NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease]; 
NSDateComponents *comps = [[[NSDateComponents alloc] init] autorelease]; 
[comps setDay:1]; 
[comps setMonth:1]; 
[comps setYear:year]; 
NSDate *start = [gregorian dateFromComponents:comps]; 
[comps setDay:31]; 
[comps setMonth:12]; 
NSDate *end = [gregorian dateFromComponents:comps]; 

NSPredicate *yearPred = [NSPredicate predicateWithFormat:@"date >= %@ && date <= %@",start,end]; 
[fetchRequest setPredicate:yearPred]; 

NSError *error = nil; 
NSArray *array = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; 
[fetchRequest release]; 
if (error) { 
    NSLog(@"Error during fetch: %@",[error localizedDescription]); 
    abort(); 
} 
int dateCount = 0, recordCount = 0; 

NSArray *dates = [array valueForKeyPath:@"@distinctUnionOfObjects.date"]; 

for (NSDate *date in dates) { 
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"date == %@",date]; 

    NSArray *records = [array filteredArrayUsingPredicate:pred]; 

    dateCount++; 
    recordCount += [records count]; 

    NSLog(@"%d record(s) with date %@",[records count],date); 
} 

NSLog(@"Record count for year is %d",recordCount); 
NSLog(@"Distinct dates count is %d",dateCount); 
} 

- (void)doSeparateTestWithYear:(int)year { 
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Record" inManagedObjectContext:self.managedObjectContext]; 
[fetchRequest setEntity:entity]; 

NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease]; 
NSDateComponents *comps = [[[NSDateComponents alloc] init] autorelease]; 
[comps setDay:1]; 
[comps setMonth:1]; 
[comps setYear:year]; 
NSDate *start = [gregorian dateFromComponents:comps]; 
[comps setYear:year+1]; 
NSDate *end = [gregorian dateFromComponents:comps]; 

NSDateComponents *oneDay = [[[NSDateComponents alloc] init] autorelease]; 
[oneDay setDay:1]; 

int dateCount = 0, recordCount = 0; 

NSDate *date = start; 
while (![date isEqual:end]) { 
    NSPredicate *dayPred = [NSPredicate predicateWithFormat:@"date == %@",date]; 
    [fetchRequest setPredicate:dayPred]; 

    NSError *error = nil; 
    int count = [self.managedObjectContext countForFetchRequest:fetchRequest error:&error]; 
    if (error) { 
    NSLog(@"Error during fetch: %@",[error localizedDescription]); 
    abort(); 
    } 

    if (count > 0) { 
    NSLog(@"%d record(s) with date %@",count,date); 
    dateCount++; 
    recordCount += count; 
    } 

    date = [gregorian dateByAddingComponents:oneDay toDate:date options:0]; 
} 

NSLog(@"Record count for year is %d",recordCount); 
NSLog(@"Distinct dates count is %d",dateCount); 

[fetchRequest release]; 
} 
: 여기

코드입니다