2010-08-27 5 views
4

Производительность основных данных на iPhone абсолютно ничтожно. Является ли индексирование полностью нарушенным или это просто плохая реализация?Как я могу улучшить производительность выборки данных на iPhone?

У меня около 21500 объектов одного типа в моем основном хранилище данных (хранилище SQLite). Объекты индексируются по UUID, который является NSString (например, выглядит примерно так: «6b09e200-07b6-11df-a245-002500a30d78»).

Единственная выборка, в которой объект существует с использованием executeFetchRequest в NSManagedObjectContext, занимает около 0,75 секунды! Это с простейшим возможным предикатом «uuid == $ UUID», где $ UUID - это строка, подобная приведенному выше примеру.

Это действительно удивительно. Если бы я хотел получить каждый объект в своем магазине, один за другим, это займет около 4,5 часов!

В любом случае, чтобы улучшить эту производительность или я должен просто отказаться от данных ядра вместе?

+0

Чтобы сравнить, я попытался собрать всю таблицу из 21 500 строк и использовать результаты для создания NSDictionary с UUID в качестве ключей. Затем я повторял весь словарь, один за другим, по каждому UUID и возвращал каждый объект. Весь этот процесс занимает всего около 5 секунд. – Mike

ответ

2

Это не будет отвечать на ваш вопрос, но может дать вам о чем подумать. Используя только SQLite на iPhone, я сильно разочаровался в производительности. Я имел дело с 8000 записей, которые занимали бы около двух минут, чтобы вставить/сортировать, возвращая все и так далее.

Играя с ним, я обнаружил, что время, необходимое для фильтрации/сортировки в памяти, было в 100 раз лучше, чем позволять делать SQLite, и я думаю, что в основном это связано с производительностью флэш-памяти.

Короче говоря, чем меньше Core Data использует флэш-память, тем лучше производительность, которую вы получите, и я не думаю, что было бы много способов сделать ее намного лучше.

+1

Я тоже сталкивался с этими проблемами, и мне удалось обойти большинство из них, выполнив как можно больше работы в памяти, а затем выполнив все вставки сразу. Кроме того, я продолжаю сохранять основные данные до тех пор, пока вы не сможете как можно дольше, поэтому, как представляется, гораздо эффективнее делать все это сразу, а не чаще. Единственное, с чем я не могу обойтись, это производительность выборки. – Mike

10

Несколько пунктов. Если для получения 21 500 строк потребуется 5 секунд, похоже, что вы работаете на более старом устройстве. Как 3G или оригинальный iPhone. Производительность памяти и ввода-вывода на них просто медленная. Вам нужно будет обращаться с вашими данными с особой осторожностью, чтобы не читать все это в памяти и делать ненужные операции ввода-вывода. Вы можете найти -setFetchBatchSize особенно полезным. Если вы работаете в 3GS, 10-20 тысяч строк управляемы, но потребуют осторожности. Если вы находитесь на ipad или iphone4, это не должно быть большой проблемой.

Вам не нужно создавать свой собственный UUID, кроме как для интерфейса с внешней системой, например с сервером. Каждый управляемый объект имеет идентификатор объекта, который представляет собой представление ООП первичного ключа. Просто передайте объект ID вокруг и делайте запросы типа @ "self =% @" или @ "self IN% @" для поиска объекта по его идентификатору или массиву идентификаторов. Вы также можете использовать -existingObjectWithID: error: для поиска только одного объекта по его объектуID, который будет быстрее, чем общий запрос выборки с общим предикатом.

Лучший способ проверить индекс используется как вы ожидаете, это запустить приложение в симуляторе с исполняемым аргументом

-com.apple.CoreData.SQLDebug 1

, который будет войти в консоль генерируется SQL. Вы должны увидеть, что некоторые вещи заканчиваются чем-то вроде t0.uuid ==?

Вы можете принять этот оператор выбора SQL и запустить его через средство запроса запросов SQLite. Запустите/usr/bin/sqlite3 против файла db в симуляторе.Есть

.explain ON explain query plan copythatsqllinehere

он должен напечатать что-то вроде 0 | 0 | ТАБЛИЦА ZFOO AS t0 с индексом то

, если он отсутствует «с индексом», то вы какой-то вопрос или с тем, как вы создали Сердечник Хранилище данных (вы уверены, что модель помечена как индекс uuid?), Или есть что-то еще с вашим запросом на выборку.

This is really surprising. If I wanted to fetch every object in my store, one by one, it >would take nearly 4.5 hours!

Я полагаю, вы могли бы сделать это таким образом, как один из самых болезненных способов. Или вы можете использовать -setFetchBatchSize: и очень быстро перебирать партии объектов.

Кроме того, имейте в виду, что каждая выборка делает I/O с базой данных, чтобы оставаться в синхронизации с тем, что сохранялись в других потоках. Извлечение - это не волшебный словарь. В то время, когда требуется выполнить наименьшую единицу ввода-вывода, существует нижняя граница. Вы захотите амортизировать количество индивидуальных запросов ввода-вывода, чтобы получить максимальную производительность. Вам придется балансировать, чтобы не перечитывать слишком много в память сразу.

Если вы по-прежнему есть проблемы, пожалуйста, сообщите об ошибке с bugreport.apple.com

  • Бен
+0

Его не старый iPhone, его 3GS. Я также пробовал его на новом iPhone 4, но производительность была не намного лучше. Я создаю свой собственный UUID именно по этой причине - мне нужно взаимодействовать с внешней системой, которая использует свои собственные UUID для обращения к данным, и мне нужно получить на основе этих UUID. – Mike

+0

Я попробую ваши предложения по рассмотрению запросов. Я думаю, что индексы не используются или не используются правильно. Время выборки кажется примерно линейным с размером таблицы. Если таблица действительно была проиндексирована, она должна выполнять двоичный поиск (или поиск по дереву), и он должен быть пропорционален журналу размера таблицы. Если это так, что моя таблица не проиндексирована, значит, это скорее ошибка, и я напишу ее с помощью apple. – Mike

+1

4.5-часовая заметка была примером того, насколько она медленная. Поскольку я получаю индивидуальные идентификаторы, нет способа получить пакеты, поэтому setFetchBatchSize бесполезен. Исключением является то, что я делаю сейчас, чтобы получить всю таблицу и построить собственный словарь, содержащий UUID каждого объекта. Извлечение СЛЕДУЕТ быть волшебным поиском словаря. По крайней мере, в современной базе данных. Нижняя граница не должна быть во втором диапазоне для таблицы среднего размера. Даже если база данных не хранит таблицы в кэше в памяти, производительность не должна меняться линейно с размером таблицы. – Mike

1

трюк с использованием основных данных является то, что только данные, которые действительно необходимы выбираются из магазина и хранятся в памяти. Я не могу себе представить, как отредактировать/переупорядочить/все 21500 строк на устройстве, таком как iPhone. Есть несколько способов, как улучшить производительность CoreData: - setFetchBatchSize - используя примитивные методы - загрузка только свойство, которые необходимы

Я помню WWDC видео сравнения SQLite & производительности CoreData и CD был явным победителем.

+0

Основные данные могут использовать двоичный файл, sqlite или память только в том случае, если он поддерживает хранилище на iPhone. Очевидно, что основные данные, использующие память, будут самыми быстрыми, но ваши данные фактически не будут сохранены на диске, поэтому в большинстве случаев это не полезно. SQLite в качестве резервного хранилища быстрее, чем плоский двоичный файл, поэтому данные ядра никогда не могут быть такими быстрыми, как SQLite, так как он всегда должен добавить некоторые накладные расходы. На самом деле, похоже, он намного медленнее. – Mike

+0

Я не уверен, как setFetchBatchSize мне поможет? Я обычно получаю только отдельные элементы данных за раз. На самом деле я не изменяю ни одну из этих 200 000 строк таблицы. Это чисто предварительная справочная таблица, которая необходима для моего приложения. (Подумайте о английском словаре с 20 000 слов в нем, вы никогда не редактируете его, но хотите, чтобы вы могли быстро найти в нем слова). – Mike

2

Я думаю, что проблема в сравнении строк намного медленнее, чем сравнение чисел для большей, если не всей базы данных.

Вы можете попытаться добавить новое свойство (столбец), aNumber, для вашего NSManagedObject, который является числом и значением, генерируемым из его UUID.

Затем построить свой запрос как «aNumber == XXX == И UUID UUID»

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

ИЛИ, вы можете попробовать индексировать UUID.

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