Ну, это компромисс с хранилищами документов. Вы можете хранить в нормализованном порядке, как в любой стандартной RDMS, и вам следует как можно больше стремиться к нормализации. Только в случае снижения производительности вы должны нарушить нормализацию и сгладить структуры данных. Компромисс между эффективностью чтения и стоимостью обновления.
Mongo имеет действительно эффективные индексы, которые могут упростить процесс нормализации, как в традиционных RDMS (большинство хранилищ документов не дают вам это бесплатно, поэтому Mongo - скорее гибрид, а не чистое хранилище документов). Используя это, вы можете создать коллекцию отношений между пользователями и событиями. Это аналог суррогатной таблицы в табличном хранилище данных. Индексируйте событие и пользовательские поля, и это должно быть довольно быстро и поможет вам лучше нормализовать ваши данные.
Мне нравится изображать эффективность выравнивания структуры по сравнению с поддержанием ее нормализации, когда дело доходит до времени, которое требуется мне для обновления данных записей по сравнению со считыванием того, что мне нужно в запросе. Вы можете сделать это с точки зрения больших цифр O, но вам не нужно быть таким причудливым. Просто напишите на бумаге несколько цифр, основанных на нескольких вариантах использования данных, и получите хорошее представление о том, сколько работы требуется.
По сути, я сначала пытаюсь предсказать вероятность того, сколько обновлений будет иметь запись в сравнении с частотой ее чтения. Затем я пытаюсь предсказать, сколько будет стоить обновление по сравнению с чтением, когда оно и нормализовано, и сплющено (или, может быть, частично из двух комбинаций, которые я могу представить ... множество вариантов оптимизации). Затем я могу судить об экономии при сохранении его на одном уровне с затратами на сбор данных из нормализованных источников. После того, как я нанес на график все переменные, если экономия от его сохранения на одном уровне сэкономит мне кучу денег, тогда я сохраню это на одном уровне.
Несколько советов:
- Если вам требуется быстрый поиск, чтобы он был быстрым и атомарным (идеально актуальным), вы можете захотеть решение, в котором вы предпочитаете уплощение, а не нормализацию и получение обновления.
- Если вам требуется быстрое обновление и немедленный доступ, тогда предпочтение отдается нормализации.
- Если вам требуются быстрые поиски, но вам не требуются совершенно обновленные данные, рассмотрите возможность создания ваших нормализованных данных в пакетных заданиях (возможно, с использованием функции map / уменьшение).
- Если ваши запросы должны быть быстрыми, а обновления редкими и не обязательно требуют, чтобы ваше обновление было доступно немедленно или требуется блокировка на уровне транзакции, чтобы он проходил 100% времени (чтобы гарантировать, что ваше обновление было записано на диск ), вы можете записать свои обновления в очередь, обрабатывая их в фоновом режиме. (В этой модели вам, вероятно, придется иметь дело с разрешением конфликтов и примирением позже).
- Профиль разных моделей. Создайте в своем коде слой абстракции для запроса данных (в некотором смысле, как ORM), чтобы позже можно было реорганизовать структуру хранилища данных.
Есть много других идей, которые вы можете использовать. Есть много отличных блогов в сети, которые идут на это, как highscalabilty.org и убедитесь, что вы понимаете теорему CAP.
Также рассмотрите кеширующий слой, такой как Redis или memcache. Я поставлю один из этих продуктов перед моим уровнем данных. Когда я запрашиваю монго (в котором хранится все нормализованное), я использую данные для построения плоского представления и сохранения его в кеше. Когда я обновляю данные, я лишу законной силы любые данные в кэше, которые ссылаются на то, что я обновляю. (Несмотря на то, что вам нужно время, чтобы аннулировать данные и данные отслеживания в кэше, который обновляется с учетом ваших коэффициентов масштабирования). Кто-то однажды сказал: «Две самые сложные вещи в информатике - это именование вещей и аннулирование кэша».
Надеюсь, это поможет!