Как уменьшить размер базы данных sqlite3 для iphone? - PullRequest
7 голосов
/ 30 декабря 2008

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

  • Переключение на сортировку символов и кодировку длины серии - новый размер БД 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). Два логических значения представляют под-словари.

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

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')

У меня есть одна идея - более эффективно кодировать буквенные частоты, например, двоично закодируйте их как большой двоичный объект (возможно, с помощью RLE, поскольку существует много нулей?). Любые идеи о том, как лучше всего достичь этого, или другие идеи, чтобы уменьшить размер? Я собираю базу данных в ruby ​​и читаю ее по телефону в цели C.

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

Ответы [ 11 ]

5 голосов
/ 31 декабря 2008

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

4 голосов
/ 31 декабря 2008

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

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

3 голосов
/ 31 декабря 2008

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

2 голосов
/ 31 декабря 2008

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

1 голос
/ 31 декабря 2008

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

РЕДАКТИРОВАТЬ: После немного больше размышлений, я думаю, что 4 бита на букву (вместо 3) было бы лучше, потому что это облегчило бы двоичную математику.

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

1 голос
/ 31 декабря 2008

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

1 голос
/ 30 декабря 2008

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

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

0 голосов
/ 31 декабря 2008

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

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

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

0 голосов
/ 31 декабря 2008

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

0 голосов
/ 31 декабря 2008

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...