3

몇 가지 테이블 뷰를 지원하는 일련의 NSFetchedResultsController가 있으며 장치에서의 성능은 몇 초 만에 매우 심했습니다. 모든 것이 메인 스레드에서 실행되기 때문에 시작시 내 응용 프로그램을 차단하므로 큰 문제는 아닙니다. 내가 조사와 술어를 밝혀SQLite 백엔드로 단정 된 NSFetchedResultsController/NSFetchRequest 성능 고정?

문제입니다 : 즉 페치 기업

NSPredicate *somePredicate = [NSPredicate predicateWithFormat:@"ANY somethings == %@", something]; 
[fetchRequest setPredicate:somePredicate]; 

, "일"을 부르는, "뭔가"엔티티와 다 대다 관계를 가지고있다. 이 술어는 결과를 특정 "무언가"와 관계가있는 것만으로 제한하는 필터입니다.

테스트를 위해 술어를 제거한 경우 가져 오기 시간 (초기 performFetch : 호출)이 4 초에서 100ms 이하로 떨어지는 경우가 있습니다. 하지만 Core Data와 NSFRC를 통해 얻을 수있는 많은 이익을 무효화 할 수밖에 없는데, 그렇지 않으면 강력한 도구처럼 보입니다.

제 질문은이 성능을 어떻게 최적화 할 수 있습니까? 술어를 잘못 사용하고 있습니까? 모델/스키마를 어떻게 든 수정해야합니까? 그리고 이것을 해결할 다른 방법은 없을까요? 이런 종류의 성능 저하가 예상됩니까? 세부 WITH

EDIT (.이 < 1킬로바이트 객체의 수백의 순서에있는) : 여기

코드입니다 : 이전

[fetchRequest setFetchLimit:200]; 
NSLog(@"before fetch"); 
BOOL success = [frc performFetch:&error]; 
if (!success) { 
    NSLog(@"Fetch request error: %@", error); 
} 
NSLog(@"after fetch"); 

업데이트 로그 (나는 일부 응용 프로그램의 비 효율성이 저하했다 성능은 여기에 있습니다. 현재 환경에서 얻을 수있는 최적의 상태로 업데이트 된 로그입니다.) :

2010-02-05 12:45:22.138 Special Ppl[429:207] before fetch 
2010-02-05 12:45:22.144 Special Ppl[429:207] CoreData: sql: SELECT DISTINCT 0, t0.Z_PK, t0.Z_OPT, <model fields> FROM ZTHING t0 LEFT OUTER JOIN Z_1THINGS t1 ON t0.Z_PK = t1.Z_2THINGS WHERE t1.Z_1SOMETHINGS = ? ORDER BY t0.ZID DESC LIMIT 200 
2010-02-05 12:45:22.663 Special Ppl[429:207] CoreData: annotation: sql connection fetch time: 0.5094s 
2010-02-05 12:45:22.668 Special Ppl[429:207] CoreData: annotation: total fetch execution time: 0.5240s for 198 rows. 
2010-02-05 12:45:22.706 Special Ppl[429:207] after fetch 
,451,515,

나는 동일 조건없이 (질문의 시작 부분에 두 줄을 주석으로) 가져 오기 할 경우 시간에

2010-02-05 12:44:10.398 Special Ppl[414:207] before fetch 
2010-02-05 12:44:10.405 Special Ppl[414:207] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, <model fields> FROM ZTHING t0 ORDER BY t0.ZID DESC LIMIT 200 
2010-02-05 12:44:10.426 Special Ppl[414:207] CoreData: annotation: sql connection fetch time: 0.0125s 
2010-02-05 12:44:10.431 Special Ppl[414:207] CoreData: annotation: total fetch execution time: 0.0262s for 200 rows. 
2010-02-05 12:44:10.457 Special Ppl[414:207] after fetch 

20 배 차이. 500ms는 그다지 좋지 않으며 배경 스레드에서 또는 다른 방법으로 최적화 할 수있는 방법이없는 것처럼 보입니다. (별 문제가되지 않는 이진 저장소로가는 것 외에는 이진 저장소 성능이 위의 200 개 개체의 조건부 쿼리에 대해 100 밀리 초임)

(이전에 다른 질문을 중첩했습니다. , 나는 지금 moved away).

+0

다 대다 관계에 대한 모든 검사와 관련이 있다고 생각하지만, 문제인 경우이 경우 핵심 데이터에 실망을 공유합니다. – gerry3

+0

하나의 임의의 생각 : 가져 오기에 대한 술어를 사용하지 마십시오. 대신 모든 것을 가져 와서 런타임 동작을 수정하십시오. 예를 들어, tableviewcontroller에서 객체가 술어와 일치하지 않으면 높이가 0 인 행을 표시합니다.)하지만 어리석은 행동입니다. – Jaanus

답변

0

이 솔루션은 성능이 훨씬 뛰어난 코어 데이터 바이너리 저장소로 전환하는 것이 었습니다. 현재 응용 프로그램 상황에서 핵심 데이터 SQLite 성능을 향상시킬 수 있는지 여부는 조사하지 않았습니다.

+1

이진 스토리가 메모리에 100 %로드되었습니다. 술어에 문제가있을만큼 충분한 데이터가 있다면, 메모리 문제에 대해 그걸 교환해야합니다. 더 나은 술어가이 문제에 대한 올바른 해결책입니다. –

+0

나는 확장 메모리 사용으로 살 수있는 충분히 작은 데이터 세트와 엔티티가 있습니다. NSFRC를 없애고 베어 본 어레이로 작업하는 것이 더 낫습니다. 특히 NSFRC 대리인이나 기타 고급 기능을 사용하지 않는다면 (Jeff LaMarche는 NSFRC가 섹션을 수정하면서 겪었던 문제점을 설명했습니다) 특히 그렇습니다. – Jaanus

4

큰 데이터베이스 나 복잡한 스키마를 위해 iPhone에서 Core Data를 사용하려는 많은 사람들에게 이것은 계속되는 문제입니다. 내 프로필에는 이와 관련된 두 가지 다른 질문에 대한 링크가 있습니다 (전체 텍스트 검색의 맥락에서).

대다수 관계에 조건자를 적용하는 것만으로 모든 앱이 개가 느린 것은 아니므로 더 많은 것이 있습니다. Apple's performance document을 참조하십시오. -com.apple.CoreData.SQLDebug를 설정하십시오.

해당하는 경우 색인이 있는지 확인하십시오. sqlite가 효율적으로 인덱스에 조인하거나 인덱스를 사용하지 못하도록 호출되는 sql 함수 (예 : 형식/유형 변환)가 없는지 확인하십시오.

많은 행이 있고 엔티티에 많은 특성이있는 경우 메모리 문제가있을 수 있습니다.하나의 엔티티를 검색에 사용되는 속성이 적은 더 작은 엔티티로 분할하고 필요할 때 나머지를 가져 오는 것을 고려하십시오.

조건부가 일대일 관계 부분보다 복잡하면 두 단계로 검색해보십시오. 예 : SQL이 비효율적으로 조인 한 다음 필터링 한 다음 조인하는 대신 필터링 할 수 있습니다. 하지만 이렇게하면 NSFetchedResultsController가 중단됩니다. 아직도, 그것은 문제에 대해 밝힐 수 있습니다.

나는 많은 foreign key 레퍼런스를 만들기 위해 attribute에 ObjectID를 꾸밀 것입니다. 코어 데이터를 심각하게 사용하지 못하도록 끔찍한 해킹을하는 것처럼 들리지만 아직 코어 데이터의 장점은 다양합니다.

역 관계를 제거하거나 추가하는 실험. 한 가지 경우에 내 쿼리가 역방향 관계없이 훨씬 빠르게 실행되는 것을 발견했습니다. 단점은 내 데이터베이스가 부풀어 오른 반대 관계를 제거했다는 것입니다.

당신이 찾은 것을 알려주세요.

+0

iPhone은 sqldebug afaik를 지원하지 않으므로 디버깅이 약간 어려워집니다. 다른 팁 주셔서 감사합니다, 시도합니다. – Jaanus

+0

이 문제가없는 바이너리 저장소의 예비 테스트를 수행 했습니까? SQLite는 실제로 필요하지 않습니다. 합리적인 규모의 데이터를 최대한으로 사용해야하기 때문에 바이너리 스토어가 나에게 도움이 될 수 있습니다. – Jaanus

+1

예, iPhone은 SQLDebug를 지원합니다. 실행 파일을 선택하십시오. 정보를 선택하십시오. 인수 추가 -com.apple.CoreData.SQLDebug 1. PS. 데이터가 작 으면 SQLite의 성능이 저하되는 것을보고 놀랐습니다.나는 당신의 코드에 뭔가 문제가 있다고 의심한다. –

0

바이너리 스토리는 전체 데이터 세트를 메모리에로드하므로 일부 장치에서 메모리 문제가 발생할 수 있습니다. 대신 술어를 다시 작성해야합니다.

귀하의 관계가 양면이므로 (오른쪽?), 반대편에서 올 수 있으며 아마도이 상황에서는 NSFetchedResultsController이 필요하지 않을 것입니다. 당신은 가정 :

MyWidgetEntity < --- >> SomethingEntity

이미 SomethingEntity의 인스턴스에 대한 참조를 가지고 있기 때문에 그것을 통해 위젯의 당신은 그냥 물어 : 상황에서

id widget = [mySomethingInstance valueForKey:@"widget"]; 

당신은 여기서

MyWidgetEntity < < - >> SomethingEntity

당신은을 통해 관련된 모든 위젯에 액세스 할 수 있습니다 : 당신이 배열에 세트를 설정하고 정렬 할 수 없기 때문에 NSFetchedResultsController가 필요하지

NSSet *widgets = [mySomethingInstance valueForKey:@"widgets"]; 

.

+0

유일한 관심사는 sectionNameKeyPath와 같은 NSFRC의 일부 편리함을 다시 구현해야한다는 것입니다.이 작업은 너무 게으르다. :) – Jaanus