База данных - разработка таблицы “событий”

После чтения подсказок из этой большой статьи Nettuts + я придумал схему таблицы, которая отделилась бы, очень энергозависимые данные из других таблиц, подвергнутых тяжелым чтениям и в то же время, понижают количество таблиц, необходимых в целой схеме базы данных, однако я не уверен, является ли это хорошей идеей, так как это не следует правилам нормализации, и я хотел бы услышать Ваш совет, вот общее представление:


У меня есть четыре типа пользователей, смоделированных в структуре Наследования Таблицы Класса, в основной "пользовательской" таблице я храню данные, характерные для всех пользователей (id, username, password, несколько flags...) наряду с некоторыми TIMESTAMP поля (date_created, date_updated, date_activated, date_lastLogin, ...).

Заключить подсказку в кавычки № 16 из статьи Nettuts + упомянуло выше:

Пример 2: у Вас есть “last_login” поле в Вашей таблице. Это обновляет каждый раз, когда пользователь входит на сайт. Но каждое обновление на таблице заставляет кэш запроса для той таблицы быть сброшенным. Можно поместить то поле в другую таблицу для хранения обновлений пользовательской таблицы к минимуму.

Теперь это становится еще более хитрым, я должен отслеживать некоторую пользовательскую статистику как

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

В моей полностью нормализованной базе данных это составляет в целом приблизительно 8 - 10 дополнительных таблиц, это не много, но я хотел бы сохранить вещи простыми, если я мог, таким образом, я придумал следующее"events"таблица:

|------|----------------|----------------|---------------------|-----------|
| ID   | TABLE          | EVENT          | DATE                | IP        | 
|------|----------------|----------------|---------------------|-----------|
| 1    | user           | login          | 2010-04-19 00:30:00 | 127.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 1    | user           | login          | 2010-04-19 02:30:00 | 127.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 2    | user           | created        | 2010-04-19 00:31:00 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 2    | user           | activated      | 2010-04-19 02:34:00 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 2    | user           | approved       | 2010-04-19 09:30:00 | 217.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 2    | user           | login          | 2010-04-19 12:00:00 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | created        | 2010-04-19 12:30:00 | 127.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | impressed      | 2010-04-19 12:31:00 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | clicked        | 2010-04-19 12:31:01 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | clicked        | 2010-04-19 12:31:02 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | clicked        | 2010-04-19 12:31:03 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | clicked        | 2010-04-19 12:31:04 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | clicked        | 2010-04-19 12:31:05 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 2    | user           | blocked        | 2010-04-20 03:19:00 | 217.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 2    | user           | deleted        | 2010-04-20 03:20:00 | 217.0.0.1 |
|------|----------------|----------------|---------------------|-----------|

В основном ID относится к первичному ключу (id) поле в TABLE таблица, я полагаю, что остальные должны быть довольно простыми. Одна вещь, которую я приехал для симпатии в этом дизайне, состоит в том, что я могу отслеживать все пользовательские логины вместо просто последнего и таким образом генерировать некоторые интересные метрики с теми данными.

Из-за растущей природы events таблица я также думал о создании некоторой оптимизации, такой как:

  • 9.: С тех пор существует только конечное число таблиц и конечного (и предопределено) количество событий, TABLE и EVENTS столбцы могли быть установкой как ENUMs вместо VARCHARs для оставления некоторого свободного места.
  • 14.: Хранилище IPs как UNSIGNED INTs с INET_ATON() вместо VARCHARs.
  • Хранилище DATEs как TIMESTAMPs вместо DATETIMEs.
  • Используйте ARCHIVE (или CSV?) механизм вместо InnoDB / MyISAM.
    • Только INSERTs и SELECTs поддерживаются, и данные сжаты на лету.

В целом, каждое событие только использовало бы 14 (несжатых) байтов, который является хорошо для моего трафика, который я предполагаю.

Профессионалы:

  • Способность хранить более подробные данные (такие как логины).
  • Никакая потребность разработать (и код для) почти дюжину дополнительных таблиц (даты и статистика).
  • Уменьшает несколько столбцов на таблицу и сохраняет энергозависимые данные разделенными.

Недостатки:

  • Нереляционный (все еще настолько же плохо как EAV):
    • SELECT * FROM events WHERE id = 2 AND table = 'user' ORDER BY date DESC();
  • 6 байтов наверху на событие (ID, TABLE и EVENT).

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

Спасибо!


@coolgeek:

Одна вещь, которую я делаю немного по-другому, состоит в том, чтобы поддержать entity_type таблицу и использовать ее идентификатор в object_type столбце (в Вашем случае, столбце 'TABLE'). Вы хотели бы сделать то же самое с event_type таблицей.

Только, чтобы быть ясными, Вы подразумеваете, что я должен добавить дополнительную таблицу, которая отображается, какие события позволяются в таблице и используют PK той таблицы в таблице событий вместо того, чтобы иметь a TABLE / EVENT пара?


@ben:

Это вся статистика, полученная из существующих данных, не так ли?

Дополнительные таблицы главным образом связаны со статистикой, но я, которого данные не делают уже, существую, некоторые примеры:

user_ad_stats                          user_post_stats
-------------                          ---------------
user_ad_id (FK)                        user_post_id (FK)
ip                                     ip
date                                   date
type (impressed, clicked)

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

Я соглашаюсь, что это должно быть отдельным, но больше потому что это - существенно различные данные. Что кто-то и что кто-то делает две разных вещи. Я не думаю, что энергозависимость так важна.

Я услышал его оба пути, и я ничего не мог найти в руководстве MySQL, которое указывает, что любой является правильным. Так или иначе я соглашаюсь с Вами, что они должны быть разделенными таблицами, потому что они представляют виды данных (с дополнительным преимуществом того, чтобы быть более описательным, чем регулярный подход).

Я думаю, что Вы пропускаете лес для деревьев, так сказать.

Предикат для Вашей таблицы был бы "идентификатором пользователя от IP IP в ДАТУ времени EVENTed к ТАБЛИЦЕ", которая кажется разумной, но существуют проблемы.

Что я имел в виду для "не настолько плохо, как EAV" то, что все записи следуют за линейной структурой, и их довольно легко запросить, нет никакой иерархической структуры, таким образом, все запросы могут быть сделаны с простым SELECT.

Относительно Вашего второго оператора я думаю, что Вы поняли меня неправильно здесь; IP-адрес не обязательно связан с пользователем. Структура таблицы должна считать что-то вроде этого:

IP-адрес (IP) сделал что-то (EVENT) к PK (ID) из таблицы (TABLE) в дату (DATE).

Например, в последней строке моего примера выше его должен считать тот IP 217.0.0.1 (некоторый администратор), удалил пользователя № 2 (чей в последний раз известный IP 127.0.0.2) в 20.04.2010 3:20:00.

Можно все еще присоединиться, скажем, к пользовательским событиям пользователям, но Вы не можете реализовать ограничение внешнего ключа.

Действительно, это - мое основное беспокойство. Однако я не полностью уверен, что может пойти не так, как надо с этим дизайном, который не мог пойти не так, как надо с традиционным реляционным дизайном. Я могу определить некоторые протесты, но, пока питание приложения с базой данных знает то, что это делает, я предполагаю, что не должно быть никаких проблем.

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

26
задан Alix Axel 20 April 2010 в 15:43
поделиться

3 ответа

Я настоятельно рекомендую этот подход. Поскольку вы предположительно используете одну и ту же базу данных для OLTP и OLAP, вы можете значительно повысить производительность, добавив несколько звезд и снежинок.

У меня есть приложение для социальной сети, в котором сейчас 65 столов. Я веду одну таблицу для отслеживания просмотров объекта (блог / сообщение, форум / ветка, галерея / альбом / изображение и т. Д.), Другую для рекомендаций по объектам и третью таблицу для суммирования операций вставки / обновления в десятке других таблиц.

Одна вещь, которую я делаю немного иначе, - это ведение таблицы entity_type и использование ее идентификатора в столбце object_type (в вашем случае - столбце TABLE). Вы бы хотели сделать то же самое с таблицей event_type.

Уточнение для Аликс - Да, вы ведете справочную таблицу для объектов и справочную таблицу для событий (это будут ваши таблицы измерений).Ваша таблица фактов будет иметь следующие поля:

id
object_id
event_id
event_time
ip_address
4
ответ дан 28 November 2019 в 17:30
поделиться

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

В моей полностью нормализованной базе данных эта добавляет примерно от 8 до 10 дополнительных таблиц

Это все статистические данные, полученные из существующих данных, не так ли? ( Обновление : хорошо, это не так, поэтому не обращайте внимания на подписку.) Почему бы это не быть просто представлениями или даже материализованными представлениями?

Это может показаться медленной операцией по сбору этой статистики, однако:

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

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

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

Я не думаю, что волатильность так важна. СУБД уже должна позволять вам размещать файл журнала и файл базы данных на разных устройствах, что делает то же самое, и конкуренция не должна быть проблемой при блокировке на уровне строк.

Безотносительно (все еще не так плохо, как EAV)

Я думаю, вам не хватает леса за деревьями, так сказать.

Предикатом для вашей таблицы будет «Идентификатор пользователя с IP-адреса во время DATE EVENTed to TABLE», что кажется разумным, но есть проблемы. (Обновление: хорошо, это что-то вроде этого.)

Вы все еще можете присоединяться, скажем, к пользовательским событиям к пользователям, но вы не можете реализовать ограничение внешнего ключа. Вот почему EAV обычно проблематичен; действительно ли что-то является EAV или нет. Обычно для реализации ограничения в вашей схеме требуется одна или две строки кода, но в вашем приложении это могут быть десятки строк кода, и если одни и те же данные доступны в нескольких местах из нескольких приложений, их можно легко умножить на тысячи строки кода. Итак, как правило, если вы можете предотвратить появление неверных данных с помощью ограничения внешнего ключа, вам гарантировано, что ни одно приложение этого не сделает.

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

Дополнительный комментарий

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

И с некоторыми оговорками вы можете создать очень успешную систему. При правильной системе ограничений вы можете сказать: «Если какое-либо приложение, вмешивающееся в базу данных, не знает, что делает, СУБД выдаст сообщение об ошибке». Это может потребовать больше времени и денег, чем у вас есть, поэтому что-то более простое, что вы можете иметь, вероятно, лучше, чем что-то более совершенное, чего вы не можете. Такова жизнь.

3
ответ дан 28 November 2019 в 17:30
поделиться

Я не могу добавить комментарий к ответу Бена, поэтому два момента...

Во-первых, одно дело использовать представления в автономной базе данных OLAP/DSS; совсем другое - использовать их в базе данных транзакций. Люди из High Performance MySQL не рекомендуют использовать представления там, где важна производительность

Что касается целостности данных, я согласен, и это еще одно преимущество использования звезды или снежинки с "событиями" в качестве центральной таблицы фактов (а также использования нескольких таблиц событий, как это делаю я). Но вы не можете разработать схему ссылочной целостности вокруг IP-адресов

0
ответ дан 28 November 2019 в 17:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: