2016-09-22 5 views
1

В настоящее время я использую coredata для моего проекта. Но когда api возвращает 54000 объектов, которые необходимо обновить, пользователь должен ждать почти 2 часа. Это основная проблема для текущего проекта, и я собираюсь использовать sqlite и больше не использовать coredata для обновления тысяч объектов.Sqlite или Core Data для обновления более 50000 записей

Правильное решение использовать Sqlite или какие-либо предложения для CoreData? Я не могу решить. Любая помощь будет отличной. Спасибо.

Вот что я делаю:

NSManagedObjectContext *privateObjectContext = [AppDelegate appDelegate].privateManagedObjectContext; 
    [privateObjectContext performBlock:^{ 

     int i = 1; 
     for (NSDictionary *item in itemlist) { 
      i++; 

      [fetchRequest setPredicate:[NSPredicate predicateWithFormat: 
             @"itemID == %@",[item objectForKey:@"item_id"] 
             ]]; 
      NSError *error; 
      NSMutableArray *inventories = [[NSMutableArray alloc]initWithArray: 
              [privateObjectContext executeFetchRequest:fetchRequest 
                       error:&error]]; 
      ItemManagedObject *itemMO; 

      if(inventories.count){ 
       itemMO = inventories.firstObject; 
      }else{ 
       itemMO = [NSEntityDescription insertNewObjectForEntityForName:@"ItemObject" 
                 inManagedObjectContext:privateObjectContext]; 
      } 
      [itemMO prepareWithDictionary:item]; 
     } 

     NSError *error; 
     if (![privateObjectContext save:&error]) { 
      completionHandler(NO); 
     } 
} 
+0

Можете ли вы описать, что вы в настоящее время обновляете объекты, которые занимают почти 2 часа?Могут быть способы улучшить его, но невозможно сказать, как, не зная, что вы делаете сейчас. –

+0

Да, нам нужно более подробно, как вы обрабатываете обновления, как часто вы сохраняете контекст, использовали ли вы инструменты для поиска узких мест, размещаете код – trapper

+0

@TomHarrington. Я добавляю код. – mega90

ответ

0

2 часа очень длинный. Это странно.

Однако вы можете массировать свой код, имея основные данные, чтобы сделать меньше работы. Гораздо меньше работы.

  1. Выполните одно выборки запроса вместо 54K выборки запросов
  2. Не называйте управляемый сеттер свойств объекта, когда значение свойства не изменится, так что ни один объект не излишне помечен как грязный, и Core Data не должны выполнять дорогостоящее, но бесполезное обновление объекта при вызове метода «save».

Это значительно сократит объем работы, выполняемой Core Data, и производительность вашего приложения.

Вторая точка проста, но очень многословна: сравнивайте значения отдельных значений со значениями словаря перед вызовом сеттеров.

Первая точка требует изменения алгоритма:

выполнить один запрос выборки, отсортированный по идентификатору (с [NSFetchRequest setSortDescriptors:])

Сортировка словарей по идентификатору (с [NSArray sortedArray ...])

Синхронизировать двух отсортированных списков (это важно, чтобы оба списка отсортированы):

NSEnumerator *itemMOEnum = [itemMOs objectEnumerator]; 
NSEnumerator *dicEnum = [dictionaries objectEnumerator]; 
ItemManagedObject *itemMO = [itemMOEnum nextObject]; 
NSDictionary *itemDic = [dicEnum nextObject]; 

while (itemDic) { 
    NSComparisonResult comparison = itemMO ? [itemDic[@"item_id"] compare:itemMO.itemID] : NSOrderedAscending; 
    switch (comparison) { 
     case NSOrderedSame: 
      // id present in both lists: update 
      [itemMO prepareWithDictionary:itemDic]; 

      itemMO = [itemMOEnum nextObject]; 
      itemDic = [dicEnum nextObject]; 
      break; 

     case NSOrderedAscending: { 
      // id present only in dictionaries: create 
      itemMO = [NSEntityDescription insertNewObjectForEntityForName:@"ItemObject" 
              inManagedObjectContext:privateObjectContext]; 
      [itemMO prepareWithDictionary:itemDic]; 

      itemDic = [dicEnum nextObject]; 
     } break; 

     case NSOrderedDescending: 
      // id present only in managed object: delete or do nothing 
      itemMO = [itemMOEnum nextObject]; 
      break; 
    } 
} 

while (itemMO) { 
    // id present only in managed object: delete or do nothing 
    itemMO = [itemMOEnum nextObject]; 
} 

И спасти.

Наконец, возможно, SQLite будет быстрее (см. https://github.com/groue/GRDB.swift/wiki/Performance, чтобы попытаться сравнить производительность Core Data с библиотеками SQLite).

Но SQLite не превратит медленный алгоритм в быстрый.

+0

Спасибо, много. Это занимает 7 минут. Я никогда не думал об использовании NSEnumerator. Простите за поздний ответ. – mega90

0

Я никогда не переделан проект основных данных в SQLite или наоборот. Поэтому я не могу сказать, есть ли разница в производительности или нет/

Однако вещь 54k = 2 часа звучит очень странно. Вы говорите об API, который заставляет меня подозревать, что сервер задействован, ваш вопрос касается баз данных. Конечно, 2 часа звучат слишком долго и заставляет задуматься, есть ли у вас проблемы с основным дизайном вашей базы данных. Например, отсутствие индексов. В зависимости от ваших запросов и базы данных, одно обновление может запускать все виды сверхмощной обработки.

Другое, хотя почему вы обрабатываете этот столбец данных на устройстве. Мне очень сложно справляться, и мне интересно, есть ли способы уменьшить уровень громкости, выборочно делать обновления или, возможно, даже лучше - перенести его на сервер.

Думаю, вам нужно переосмыслить свой вопрос. Предоставьте больше информации о базе данных, что вы делаете с ней и почему.

+0

Как @jrturton сказал: «Если itemList содержит 54 000 объектов, тогда вы выполняете 54 000 выборок в постоянном хранилище, чтобы каждый раз проверять один идентификатор». , Я не знал этой рабочей системы coredata. Я думаю, ответ на 2 часа - это. – mega90

0

CoreData - это не менеджер баз данных, а граф объектов и постоянный менеджер. CoreData может хранить свои объекты в базе данных sqlite, а также в файлах XML или двоичном файле (разработчик выбирает вариант, наиболее подходящий для его нужд).

Основное отличие CoreData от менеджера баз данных заключается в том, что для доступа к объекту с CoreData CoreData необходимо создать объект Object-C/Swift.

Sqlite может получить доступ к части данных без необходимости извлекать полную запись, содержащую данные.

И тогда CoreData необходимо поддерживать реляционный граф между объектами (отношения между двумя классами CoreData и в общем, в обоих направлениях).

Итак, при обновлении объектов 54k вы запрашиваете CoreData для создания объектов 54k (в памяти) и, в конечном счете, для обновления их отношений.

Это очень тяжелая работа для CoreData на мобильных устройствах.

Возможно, ваша модель CoreData некорректно оптимизирована. Возможно, вам следует регулярно сохранять контекст CoreData и скрывать блокнот CoreData (часть памяти, содержащую фактически прочитанные или обновленные объекты).

Но, по моему опыту, CoreData не подходит для работы с тяжелыми данными.

Повторное выполнение ваших потребностей с помощью sqlite может быть довольно сложной задачей, если вы хотите, чтобы иметь возможность повторно создавать объекты classe из sqlite-записей и управлять довольно автоматическими отношениями, но это выполнимо. Я сделал это по некоторым проектам. Это добавляет преимущества иметь модельный объект, который более совместим с другой платформой как Android, например, поскольку sqlite доступен на многих платформах.

Еще одна вещь: sqlite более подходит для использования в нескольких потоках. CoreData более трогательно в этом и нуждается в одном контексте по потоку и, в конечном счете, в некоторой синхронизации контекстов.

+0

Спасибо за объяснение, теперь я понимаю основные данные и SQL-различия лучше. Иногда лучше спросить и получить больше мнений, чтобы понять проблему и научиться вещам, а затем просто искать в Интернете и попытаться получить представление (я искал, но теперь я понял, что лучше) – mega90

1

Основные данные предоставляют NSBatchUpdateRequest, что позволяет производить обновления непосредственно в постоянном хранилище без привлечения экземпляров и обработки управляемых объектов в памяти.

Вы должны запустить этот код, используя также инструмент для работы с основными данными. Если itemList содержит 54 000 объектов, вы выполняете 54 000 выборок в постоянном хранилище, чтобы каждый раз проверять один идентификатор. Было бы намного быстрее получить все идентификаторы вверх, а затем проверить результаты в памяти, чем выполнять повторные запросы выборки - этот код будет почти таким же медленным в сыром SQL, как и в Core Data.

Этот код также выглядит не так:

ItemManagedObject *itemMO; 

if(itemMO.count){ 

Он никогда не будет так, что если тест, если вы не пропустили строчку где-нибудь.

+0

ups.while Я редактировал свой код для вопроса о стеке, i написал это неправильно. Но каждый 3 или 4 столбца могут иметь разные значения. Не из них такие же. Поэтому NSBatchUpdateRequest бесполезен для этой ситуации. Но спасибо в любом случае. С ответами я узнал больше о различии между sqlite coredata с лучшими объяснениями. Поэтому мне будет полезно преобразовать структуру в использование sqlite из coredata. – mega90

Смежные вопросы