Как уменьшить размер базы данных sqlite3 для iPhone?

edit: большое спасибо за все ответы. Вот результаты после применения оптимизаций до сих пор:

  • переключение на сортировку символов и кодировку длины запуска-новый размер DB 42M
  • падение индексов на булевых-новый размер БД 33M

действительно хорошая часть-это не требует каких-либо изменений в коде iphone

у меня есть iphone приложение с большим словарем в формате sqlite (только для чтения). Я ищу идеи для уменьшения размера файла БД, который в настоящее время очень большой.

вот количество записей и результирующий размер БД sqlite:

franks-macbook:DictionaryMaker frank$ ls -lh dictionary.db
-rw-r--r--  1 frank  staff    59M  8 Oct 23:08 dictionary.db
franks-macbook:DictionaryMaker frank$ wc -l dictionary.txt
  453154 dictionary.txt

...в среднем около 135 байт на запись.

вот моя схема БД:

create table words (word text primary key, sowpods boolean, twl boolean, signature text)
create index sowpods_idx on words(sowpods)
create index twl_idx on words(twl)
create index signature_idx on words(signature)

вот некоторые примеры данных:

photoengrave|1|1|10002011000001210101010000
photoengraved|1|1|10012011000001210101010000
photoengraver|1|1|10002011000001210201010000
photoengravers|1|1|10002011000001210211010000
photoengraves|1|1|10002011000001210111010000
photoengraving|1|1|10001021100002210101010000

последнее поле представляет частоты букв для анаграммы извлечение (каждая позиция находится в диапазоне 0..9). Два логических значения представляют собой словари sub.

мне нужно сделать такие запросы, как:

select signature from words where word = 'foo'
select word from words where signature = '10001021100002210101010000' order by word asc
select word from words where word like 'foo' order by word asc
select word from words where word = 'foo' and (sowpods='1' or twl='1')

одна идея у меня есть, чтобы кодировать частоты букв более эффективно, например, двоичное кодирование их как blob (возможно, с RLE, так как есть много нулей?). Любые идеи о том, как лучше всего достичь этого, или другие идеи, чтобы уменьшить размер? Я создаю БД в ruby и читаю его по телефону в objective C.

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

11 ответов


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


вы пробовали ввести команду "вакуум", чтобы убедиться, что у вас нет лишнего места в БД, которую вы забыли перезаписать?


удалите индексы на sowpods и twl-они, вероятно, не помогают вашему времени запроса и определенно занимают много места.

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


как совершенно другой подход, вы можете попробовать использовать bloom filter вместо всеобъемлющей базы данных. В принципе, фильтр bloom состоит из множества хэш-функций, каждая из которых связана с битовым полем. Для каждого юридического слова вычисляется каждая хэш-функция и задается соответствующий бит в соответствующем битовом поле. Недостатком является теоретически возможно получить ложные срабатывания, но их можно минимизировать/практически устранить с достаточным количеством хэшей. Плюсом является огромная экономия пространства.


создатель SQLite продает версию SQLite, которая включает сжатие базы данных (и шифрование). Это было бы идеально.


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

в противном случае я бы рекомендовал хранить ваши данные в основном в сжатом формате и распаковки "на лету".


как текстовое поле, signature в настоящее время использует не менее 26 * 8 байт на запись (208 байт), но если вы должны были упаковать данные в битовое поле, вы, вероятно, могли бы уйти только с 3 битами на букву (уменьшая максимальную частоту на букву до 7). Это означает, что вы можете упаковать всю подпись в 26 * 3 бит = 78 бит = 10 байт. Даже если вы используете 4 бита на букву (для максимальной частоты 15 на букву), вы будете использовать только 104 бита (13 байт).

изменить: после немного больше мысли, я думаю, что 4 бита на букву (вместо 3) было бы лучшей идеей, потому что это облегчило бы двоичную математику.

EDIT2: чтение документов на типы данных SQLite, кажется, что вы можете просто сделать поле "Подпись" 26 столбцов типа INTEGER и SQLite будет делать все правильно и использовать только столько битов, сколько требуется для хранения значения.


правильно ли я считаю, что у вас есть около 450K таких слов в вашей базе данных ?

Я понятия не имею об iPhone, ни серьезно о sqlitem, но... пока sqlite не позволяет сразу сохранить файл как gz (возможно, уже делает это внутренне? нет, не выглядит так, когда вы говорите, что это около 135 b за вход. даже с обоими индексами), я бы отошел от табличного подхода, сохранив его "вручную" в подход словарь сжатие и построить остальные на лету и в памяти. Это должно очень хорошо работать с вашим типом данных.

подождать... Вы используете эту подпись, чтобы разрешить fulltextsearching или ошибочное распознавание ? Бы полнотекстовый поиск на sqlite не устарело это поле ?


Как отмечалось, хранение "подписи" более эффективно кажется хорошей идеей.

однако, похоже, вы также можете получить тонну экономии места, используя какую - то таблицу поиска для слов-поскольку вы, похоже, берете корневое слово, а затем добавляете "er", "ed", "es" и т. д. Почему бы не иметь столбец с числовым идентификатором, который ссылается на корневое слово из отдельной таблицы поиска, а затем отдельный столбец с числовым идентификатором, который ссылается на таблицу общих суффиксов слов, которые добавлено к основному слову.

Если бы были какие-либо трюки вокруг хранения сокращенных версий подписей для нескольких записей с одним корневым словом, вы также могли бы использовать их для уменьшения размера сохраненных подписей (не уверен, какой алгоритм производит эти значения)

Это также, кажется, имеет большой смысл для меня, поскольку у вас есть столбец "word" в качестве первичного ключа, но даже не индексируйте его - просто создайте отдельный числовой столбец, который является первичным идентификатором для таблица.


МММ... айфон... разве у него нет постоянного подключения к данным ? Я думаю, что именно здесь webapplication/webservice может удобно прыгать. Переместите большую часть своей бизнес-логики на веб-сервер (у него будет реальный SQL с FTS и looooots памяти) и принесите эту информацию онлайн клиенту на устройстве.


Как упоминалось в другом месте, потеряйте индексы в логических столбцах, они почти наверняка будут медленнее (если используются вообще), чем сканирование таблицы, и будут использовать пространство без необходимости.

Я бы рассмотрел применение простого сжатия к словам,кодирование Хаффмана довольно хорошо для такого рода вещей. Кроме того, я бы посмотрел на подписи: сортируйте столбцы в порядке частоты букв и не беспокойтесь о сохранении конечных нулей, что может быть подразумеваемо. Думаю, ты мог бы. Хаффман-Закодируйте и их тоже.

всегда предполагая, что ваши закодированные строки не расстраивают SQLite, конечно.