У меня есть готовое корпоративное приложение (non-AppStore) для iOS для iPad, которое мне нужно для рефакторинга (он был написан другим разработчиком, моим предшественником в моей текущей работе).
Это приложение извлекает свои данные через JSON с сервера, имеющего базу данных MSSQL. В схеме базы данных имеется около 30 таблиц, наиболее емкими являются: Клиент, Город, Агентство, каждый из которых имеет около 10.000 записей, а дальнейший рост ожидается в будущем. После получения JSON (одна пара запросов и ответа JSON для каждой таблицы) - она сопоставляется с CoreData - процессом, который также включает в себя объединение друг с другом соответствующих объектов CoreData (Клиент, Город, Агентство и другие) друг с другом, т.е. устанавливая отношения между этими объектами на уровне CoreData.
Сам по себе проект-выборка CoreData (или часть read-part) сильно оптимизирован - он использует, я думаю, почти все возможные улучшения производительности и памяти CoreData, поэтому уровень приложения UI очень быстрый и отзывчивый, так что я считаю его работу полностью удовлетворительной и адекватной.
Проблема - это процесс подготовки уровня CoreData, то есть процесс синхронизации между сервером: требуется слишком много времени. Рассмотрим 30 сетевых запросов, в результате получивших 30 пакетов JSON ( "пакет", я имею в виду "одна таблица - один JSON" ), которые затем отображаются на 30 объектов CoreData, которые затем склеиваются (соответствующие отношения CoreData устанавливаются между ними). Когда я впервые увидел, как все это делается в этом проекте (слишком медленно), первая идея, которая появилась у меня в голове, заключалась в следующем:
"Впервые выполняется полная синхронизация (время первого запуска приложения) - выполнить выборку всей базы данных в, например, в одном архиве (что-то вроде дампа базы данных), а затем как-то импортировать его в целом на Землю основных данных".
Но потом я понял, что даже если такая передача такого однофакторного дампа была возможна, CoreData все равно потребует от меня выполнить склейку соответствующих объектов CoreData, чтобы установить соответствующие отношения между ними, так что трудно представить что я мог бы воспользоваться результатами, если бы я полагался на эту схему.
Кроме того, мой коллега предложил мне рассмотреть SQLite как полную альтернативу Core Data, но, к сожалению, у меня нет опыта его использования, поэтому я полностью слеп, чтобы предвидеть все последствия такого серьезного проектного решения ( даже если процесс синхронизации очень медленный, мое приложение действительно работает, особенно его производительность пользовательского интерфейса очень хороша сейчас). Единственное, что я могу себе представить о SQLite, который, в отличие от Core Data, не заставит меня приклеить дополнительные отношения на стороне клиента, потому что SQLite имеет свою старую систему внешнего ключа, не так ли?
Итак, вот вопросы (Респонденты, пожалуйста, не смешивайте эти моменты, когда вы отвечаете - слишком много путаницы у меня есть обо всех них):
-
Есть ли у кого-нибудь такой опыт применения подхода "первый раз крупный импорт всей базы данных" таким образом, как я описал выше? Я был бы очень благодарен за информацию о любых решениях, если они будут использовать пару JSON ↔ CoreData или нет.
-
Имеет ли Core Data некоторый глобальный механизм импорта, который может позволить массовое создание соответствующей схемы из 30 таблиц (возможно, используя какой-то конкретный источник, отличный от "30 пакетов JSON", описанный выше) без необходимости настройки соответствующие отношения для 30 объектов?
-
Есть ли возможности ускорить процесс синхронизации, если 2) невозможно? Здесь я имею в виду улучшения текущей схемы JSON ↔ CoreData, используемой моим приложением.
-
Переход на SQLite: следует ли рассматривать такую миграцию? Что я получу от этого? Как может выглядеть весь процесс репликации → передача- > клиентские препараты?
-
Другие альтернативы CoreData и SQLite - что они могут быть или похожи?
-
Любые другие мысли или видения, которые могут возникнуть у вас о ситуации, описанной мной?
ОБНОВЛЕНИЕ 1
Хотя ответ, написанный Mundi, хорош (один большой JSON, "Нет" для использования SQLite), мне все еще интересно, есть ли какие-либо другие сведения о проблеме, которую я описал.
ОБНОВЛЕНИЕ 2
Я попытался использовать свой русский английский, чтобы наилучшим образом описать свою ситуацию в надежде, что мой вопрос может стать довольно понятным для всех, кто его прочитает. К этому второму обновлению я попытаюсь предоставить ему несколько руководств, чтобы сделать мой вопрос еще более понятным.
Пожалуйста, рассмотрите две дихотомии:
- Что можно/следует использовать в качестве слоя данных для клиента iOS - CoreData vs SQLite?
- Что можно/следует использовать в качестве транспортного уровня - JSON (один-JSON-at-once, как это было предложено в ответе, возможно, даже в zip файле) или какие-то самолеты DB (если это даже возможно, конечно) Обратите внимание, что я также задаю это в своем вопросе).
Я думаю, что это довольно очевидный "сектор", который формируется путем пересечения этих двух дихотомий, выбирая CoreData из первого, а JSON со второго - это самый распространенный дефолт в мире разработки iOS, а также он используется по моему приложению из этого вопроса.
Сказав это, я заявляю, что буду благодарен за любые ответы, касающиеся пары CoreData-JSON, а также ответы, рассматривающие использование любых других "секторов" (как насчет выбора SQLite и какого-то своего подхода к дампам, почему?)
Также важно отметить, что я не хочу просто отбрасывать текущую опцию для некоторых других альтернатив, я просто хочу, чтобы решение быстро работало на этапах синхронизации и UI его использования. Поэтому ответы об улучшении текущей схемы, а также ответы, предлагающие другие схемы, приветствуются!
Теперь см. следующее обновление №3, в котором содержится более подробная информация о текущей ситуации CoreData-JSON:
ОБНОВЛЕНИЕ 3
Как я уже сказал, в настоящее время мое приложение получает 30 пакетов JSON - один пакет для всей таблицы. Давайте возьмем емкие таблицы, например: Client, Agency, City.
Это основные данные, поэтому, если в записи client
есть непустое поле agency_id
, мне нужно создать новый объект Core Data класса Agency (NSManagedObject subclass)
и заполнить его данными записи JSON, поэтому мне нужно уже иметь соответствующий объект Core Data для этого агентства класса Agency (NSManagedObject subclass)
, и, наконец, мне нужно сделать что-то вроде client.agency = agency;
, а затем вызвать [currentManagedObjectContext save:&error]
. Сделав это, позже я могу попросить этого клиента получить его и попросить его свойство .agency
найти соответствующий объект. Надеюсь, я полностью прав, когда я это делаю.
Теперь представьте, что этот шаблон применяется к следующей ситуации:
Я только что получил следующие 3 отдельных пакета JSON: 10000 клиентов и 4000 городов и 6000 агентств (у клиента есть один город, в городе много клиентов, у клиента есть агентство, агентство имеет много клиентов, агентство имеет один город, в городе много агентства).
Теперь я хочу установить следующие отношения на уровне основных данных: я хочу, чтобы мой клиентский объект client
был подключен к соответствующему городу и соответствующему агентству.
Текущая реализация этого в проекте очень уродливая:
-
Так как порядок зависимостей следующий: City → Agency → Client i.e, сначала нужно запечь город, приложение начинает создавать объекты для Города и сохраняет их в Core Data.
-
Затем он имеет дело с JSON агентств: он выполняет итерацию через каждую запись JSON - для каждого агентства создается новый объект
agency
и егоcity_id
, он извлекает соответствующий объектcity
и подключается он используетagency.city = city
. После завершения итерации по всем массивам JSON агентства сохраняется текущий контекст управляемого объекта (фактически - [managedObjectContext save:] выполняется несколько раз, каждый после обработки 500 записей). На этом этапе очевидно, что получение одного из 4000 городов для каждого клиента для каждого из 6000 агентств имеет огромное влияние на производительность всего процесса синхронизации. -
Затем, наконец, он касается JSON клиентов: как и в предыдущем 2-м этапе, он выполняет итерацию через весь массив JSON из 10000 элементов и один за другим выполняет выбор соответствующих агентств и городов ZOMG, и это влияет общая производительность аналогична предыдущему этапу 2.
Все это очень плохо.
Единственная оптимизация производительности, которую я вижу здесь, заключается в том, что первый этап может оставить большой словарь с идентификаторами городов (я имею в виду NSNumber реальных идентификаторов) и ошибочными объектами города как значениями), поэтому можно было бы предотвратить уродливые найтипроцесс следующего этапа 2, а затем сделать то же самое на этапе 3 с использованием аналогичного кэширующего трюка, но проблема в том, что между всеми 30 таблицами, которые только что описаны, существует гораздо больше отношений [Client-City, Client-Agency, Agency -City], поэтому окончательная процедура, связанная с кэшированием всех объектов, скорее всего, ударит по запасам устройств iPad для моего приложения.
ОБНОВЛЕНИЕ 4
Сообщение для будущих респондентов: я изо всех сил старался сделать этот ответ достаточно подробным и хорошо сформированным, и я действительно ожидаю, что вы ответите на подробные ответы. Было бы здорово, если бы ваш ответ действительно рассмотрел сложность проблемы, обсуждаемой здесь, и дополнял мои усилия, которые я сделал, чтобы сделать мой вопрос ясным и общим как можно больше. Благодарю.
ОБНОВЛЕНИЕ 5
Связанные темы: Основные данные на клиенте (iOS) для кэширования данных из стратегии сервера, Попытка сделать POST запросить с RestKit и отобразить ответ на основные данные.
ОБНОВЛЕНИЕ 6
Даже после того, как больше не возможно открыть новые щедрости, и есть принятый ответ, я по-прежнему буду рад увидеть любые другие ответы, содержащие дополнительную информацию о проблеме, которая адресована этим темам. Спасибо заранее.