Как уменьшить размер базы данных 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, конечно.