Необходимо хранить сущность user с N полями, где N неизвестное заранее число, 1<=N<=2000. Многие поля будут повторяться (ФИО, email, тел. номер), но их наличие не гарантировано. Есть необходимость в любое время получить все существующие в типы полей в user.
Верхний потолок планируемого масштабирования - несколько миллионов записей.
Требуется высокая гибкость выборок.
Встал вопрос в выборе БД:
Реляционная база, PostgreSQL. Варианты хранения:
1. таблица user: (id + поле JSON) + отдельная таблица для хранения списка полей. Работать это дело, как я понимаю, будет очень-очень медленно.
2. таблица user: (id) + таблица field(primary key, name, value, user_id), обернутое внешними ключами сверху. Проблемы: избыточность данных -- если у миллиона юзеров есть ФИО, в таблице field будет миллион полей вида:
[ 999 | ФИО | Иван Иванович | 555 ], ... , [ 9999 | ФИО | Петр Петрович | 666 ], ... .
3. таблица user: (id) + таблица field (id, name) + таблица field_value (user_id, field_id, value). Плюсы: минимальная избыточность данных, очень просто получить список всех полей. Минусы: количество строк в таблице field_value будет стремиться к count(user) * count(field), что при миллионе user и тысяче field будет равняться миллиарду. Это ведь слишком много?
Документоориентированная БД (mongo)
Плюсы: Модель хранения идеально подходит под наши данные.
Минусы: в целом начитался большое количество страшилок про монгу, отношение слегка предвзятое; отсутствие опыта; опасение в будущем столкнуться со слишком несвязанными данными. (Хотелось бы иметь возможность безболезненно связывать данные с другими сущностями (товары/теги/etc)
Собственно, есть понимание, что ошибка сейчас может очень дорого обойтись в последствии, так что прошу совета. Стоит ли воспользоваться одним из перечисленных или незамеченных способов с sql-базой, или же стоит приступить к изучению Mongo?
Мне кажется вы сильно перенагрузили таблицы, думаю надо разбить ещё на какие либо сущности, личные данные все же лучше таскать с собой, тот же мыльный ящик, чтоб например пароль востановить , больше таблиц, больше связей
Дмитрий, user в моём случае - это не пользователь сайта, это объект отчётности. Контактные данные могут быть, а могут и не быть, и на этапе кода и проектирования предсказать, хотя бы примерно, какие поля будут - невозможно. в минимальной конфигурации у user только одно поле -- условный primary key
Опишите, какие именно выборки ожидаются. По одному пользователю, по 100, агрегация по всем 1 млн? Также, все поля о пользователе нужны всегда или только часть?
при миллионе user и тысяче field будет равняться миллиарду. Это ведь слишком много?
В байтах померяйте. Какая разница, в какой структуре будут лежать эти данные, если их объективно, скажем, 100 Гб. Много это или мало для вас, зависит от требований к выборкам, железа и т.д.
os9, агрегация по всем пользователям. Большая часть операций требует только части полей пользователя.
ну, если исходить из того, что ключи в таблице user_field_value будут 4-байтовыми, а значение будет укладываться в 256-байтную строку, получится примерно 250 гигов только на эту табличку. Ни капли не смертельно с точки зрения хранения, а с точки зрения выборок не хватает опыта в использовании большого объёма данных с базами данных, для того чтобы +- корректно оценить насколько всё это чудо будет шустро бегать.
1. Просто для понимания - а что за текстовые 2 тыс. полей у вас, по которым требуется агрегация по всем пользователям? Когда числовые признаки, то можно считать сумму, кол-во ненулевых и т.д. А по строкам какая будет агрегация?
2. Если действительно агрегация по всем пользователям, и нужна только часть полей, то смотрите в торону columnstore на любой СУБД. Такие таблицы умеют хорошо сжимать данные в столбцах, и за счет компактного хранения агрегация происходит быстрее.
3. Но сначала можно попробовать упомянутую тут модуль EAV на реляционной СУБД, только нужно продумать, как организовать хранение. Наверно, кластерный индекс будет по (ИД Свойства, ИД Пользователя), чтоб при выборке по одному "ИД Свойства" по всем пользователям у вас нужные данные оказывались более компактно расположены на страницах, т.е. требовалось бы меньшее количество чтений.
Этот опыт вы можете легко поставить. Результат зависит от вашего железа, реальных объемов, количества выбираемых свойств пользователя.
os9,
1. Текстовые поля не все, в расчете брал их просто для округления в большую сторону
2. Буду смотреть, спасибо!
3. Да, пока в мыслях лидирует EAV, но хочется попытаться втиснуться colum-oriented бд
Если нужна одна таблица без джоинов, несколько миллионов записей, то храните просто таблицей в column oriented СУБД Clickhouse. 2000 столбцов там норма.
Задуматься о производительность придётся после миллиардов записей
Ну справедливости ради я бы заметил, что Join в ClickHouse все же есть. Кроме того часть запросов с Join можно трансформировать в запрос с подзапросом.