SQLite: как лучше оптимизировать таблицу (и нужно ли вообще)?
Допустим, есть что-то типа ежедневника, куда пользователь регулярно делает записи. Он делит эти записи на категории, например: «дела», «покупки», «контакты» и т. д., ну как ему удобно, так и делит, он решает это сам. Может вообще все в одну категорию записывать. Этот «ежедневник» представлен в виде сайта, пользователь кликает на нужную категорию, ему на страницу подгружаются соответствующие записи, он может их редактировать, удалять или добавить новые.
Короче, мы создаем что-то вроде CMS.
Технически это выглядит так: на сервере есть база данных sqlite с таблицей, куда заносятся все записи пользователя. В таблице несколько колонок, ну например:
id записи | название | текст | дата создания | категория
Соответственно, необходимо будет проводить следующие операции: добавление записи, редактирование, удаление, поиск записей по категории и по id. Самой популярной операцией предполагается поиск (но это только гипотеза).
Размер одной записи может варьироваться от самых минимальных значений (несколько символов просто) до 150-200 кб данных.
Количество таких строк тоже может быть очень разным, от нескольких десятков до нескольких тысяч. Давайте, например, решим, что максимум он может внести 10.000 строк. При этом максимальный размер базы будет ограничен 500 мб, так что он не может внести 10.000 строк по 200кб, к примеру.
Запросы к БД будут делаться не очень часто. Ну, скажем так, с человеческой скоростью, то есть не будет 1000 запросов в секунду. Вот как пользователь ходит по сайту, нажал кнопку категории = запрос, отредактировал что-то, отправил изменения = запрос. Может где-то будет несколько запросов подряд, но не больше.
Чтобы не переусложнять с размерами и т.д., давайте будем считать, что под каждого пользователя создается своя база данных, и размер мы считаем размером файла.
Так вот, мы имеем 2 предельных варианта: 1 — пользователь внес одну минимальную запись; 2 — пользователь внес 10.000 записей и занял 500мб.
Да, на практике скорее всего будет что-то среднее, но надо, чтобы обе эти ситуации отрабатывались. И если с 1 проблем не возникает, то вот 2 вызывает вопросы.
Я понимаю, что вроде как 500мб и 10.000 строк это ну не настолько прямо много, да и сложные операции с данными не планируются. С другой стороны, я не совсем понимаю, что значит «много», и с каких значений могут начаться проблемы с производительностью, если учесть, что запросы к БД формируются корректно, чтобы обойтись без лишних обращений.
Очевидно, что вопрос производительности зависит от вычислительной мощности, и на суперкомпьютере гугла все это будет происходить незаметно, а на ЭВМ мохнатого года - нет. Поэтому вопрос больше в том, будет ли толк от вообще какой-либо оптимизации такой базы данных?
Я вижу 3 возможных варианта:
Забить на оптимизацию. Просто оставить как есть, пусть будет таблица, 10.000 записей, 500мб, совершать запросы прямо в лоб, без изобретения велосипедов. Отчасти я склоняюсь к этому варианту.
Попробовать поработать с индексами. Но индексировать тут как будто и нечего, сложные запросы я не делаю, а если проиндексировать категории, например, то боюсь, что только хуже будет.
Разделить таблицу на несколько небольших. Вот над этим вариантом думаю больше всего. Сделать отдельную таблицу под каждую категорию. С одной стороны, это не совсем логично, потому что все записи по идее имеют 1 сущность, и правильнее держать их в 1 таблице. Более того, это местами усложняет код, появляется дополнительная ниша для возникновения ошибок. С другой стороны, мне по сути никогда не надо обращаться к таблице целиком. Обращение идет либо по категориям, либо по id, но с учетом, что категория записи уже известна. Так что, если я разбиваю таблицу таким образом, то не теряю в функционале, но получаю гибкость оптимизации. То есть, теперь, если какая-то категория начинает тормозить, пользователь просто может создать другую = создать новую таблицу в БД. А поскольку мы решили, что пользователь в этой базе 1, то вряд ли есть опасность замусорить ее кучей таблиц.
Так что вот, вопрос в оптимизации БД. Что стоит предпринимать в описанной ситуации?
Ну и вообще концептуально о пределах, когда об этой оптимизации стоит задумываться? Потому что очевидно, что если в таблице 1 запись, то оптимизировать нечего. А если 10? А если 100, 1000, 10000… Есть ли какие-то общепринятые признаки того, что стоит задуматься об оптимизации? Ну кроме того, что БД уже тормозит, чтобы предвидеть ситуацию.
Ответы (3 шт):
10_000 записей даже для простой БД - это ерунда. Нормальные БД моментально ищут среди миллионов записей, если грамотно индексы построены. А среди тысяч записей - даже и без индексов. Вот строки размером по 200кб - это ненормально. Такие данные обычно в БД не кладут. Вам по ним нужно искать или их нужно просто хранить? Если просто хранить, то такие большие объекты:
- Хранят в отдельной таблице БД, лежащей в отдельной файловой группе, специально выделенной под большие объекты.
- Либо хранят вообще отдельно от БД, например, в виде файлов в файловой системе, а в БД хранят названия этих файлов.
- Сжимают любым методом сжатия и хранят в БД в сжатом виде. Некоторые БД сами умеют сжимать данные, тогда "ручное" сжатие не нужно.
- Используют специализированные БД, специально предназначенные для хранения больших строк/документов/xml/json или что там у вас. В этом случае можно и искать по этим большим объектам, специализированные БД это умеют.
Прежде всего нужно понять - что это за большие объекты у вас, и нужен ли вам поиск в БД по их содержимому. Количество записей, повторюсь - не проблема. А вот размер записей - это проблема.
Вообще вопрос - чистый opinion-based. Ну да ладно.
Ввод и корректировка исключительно интерактивны. Следовательно, на производительность этих операций можно смело забить.
Поиск по id, который, как я понимаю, предполагается первичным ключом-автоинкрементом, тоже проблем не вызывает. Хотя я сильно сомневаюсь, что кто-то будет им пользоваться.
Поиск по категории. Тут всё зависит от типа поиска - по префиксу, по произвольной точной подстроке, полнотекстовый. В первом случае достаточно обычного индекса по вменяемому префиксу значения, в остальных придётся использовать FTS-5. И, сто пудов, захочется динамического поиска - вот с ним поосторожнее.
Ещё - поиск по категории, скорее всего, будет ещё дополняться фильтром по дате. В первом случае просто используете составной индекс, во втором - тестируем дополнительный индекс по дате, возможно, он будет использоваться, хотя мне сомнительно, и, скорее всего, сервер будет выполнять просто фуллскан результата полнотекста. Тут лучше подумать о другой СУБД. Хотя записей мало, авось и прокатит. Тут скорее надо будет думать над UI, чтобы не передавать всю запись в список, хватит и помещающегося на экране префикса. А уж на экран отображения одной отдельной выбранной записи можно передать и всё.
10k записей - это ни о чём. 500 метров для SQLite - это и не много и не мало. Средненько.. но уже в принципе в районе той границы, когда пора думать о смене СУБД на нормальную клиент-серверную.
А ещё можно будет подумать о локальном, на стороне клиента, хранении рабочей копии, и на сервере соответственно эталонной. С организацией двусторонней синхронизации.
Всё строго ИМХО, конечно.
- 10000 записей для БД - это вообще ни о чем. Время выборки по ключам не зависит от величины записи, даже если Вы используете строковые типы для ключевых полей - они давно и эффективно заменяются хэшами. Серьезно повлиять на время выборки из БД может только
LIKE
по какому-то большому текстовому полю. - На каждого пользователя свой файл БД - тоже не очень идея.
- Быстрые диски.
- Выбор движка самой БД, есть такие решения, как Кликхаус, позволяющие обрабатывать огромное количество записей за минимальное время.