После чтения подсказок из этой большой статьи 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
таблица я также думал о создании некоторой оптимизации, такой как:
TABLE
и EVENTS
столбцы могли быть установкой как ENUM
s вместо VARCHAR
s для оставления некоторого свободного места.IP
s как UNSIGNED INT
s с INET_ATON()
вместо VARCHAR
s.DATE
s как TIMESTAMP
s вместо DATETIME
s.ARCHIVE
(CSV
?InnoDB
/ MyISAM
. INSERT
s и SELECT
s поддерживаются, и данные сжаты на лету.В целом, каждое событие только использовало бы 14 (несжатых) байтов, который является хорошо для моего трафика, который я предполагаю.
SELECT * FROM events WHERE id = 2 AND table = 'user' ORDER BY date DESC();
ID
, TABLE
и EVENT
).Я более склонен пойти с этим подходом, так как профессионалы, кажется, явно перевешивают недостатки, но я все еще немного отказываюсь... Я пропускаю что-то? Каковы Ваши мысли об этом?
Спасибо!
Одна вещь, которую я делаю немного по-другому, состоит в том, чтобы поддержать entity_type таблицу и использовать ее идентификатор в object_type столбце (в Вашем случае, столбце 'TABLE'). Вы хотели бы сделать то же самое с event_type таблицей.
Только, чтобы быть ясными, Вы подразумеваете, что я должен добавить дополнительную таблицу, которая отображается, какие события позволяются в таблице и используют PK той таблицы в таблице событий вместо того, чтобы иметь a TABLE
/ EVENT
пара?
Это вся статистика, полученная из существующих данных, не так ли?
Дополнительные таблицы главным образом связаны со статистикой, но я, которого данные не делают уже, существую, некоторые примеры:
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
механизм устройства хранения данных здесь, единственная вещь - это, не поддерживает FK
s (ни один UPDATE
s или DELETE
s).
Я настоятельно рекомендую этот подход. Поскольку вы предположительно используете одну и ту же базу данных для OLTP и OLAP, вы можете значительно повысить производительность, добавив несколько звезд и снежинок.
У меня есть приложение для социальной сети, в котором сейчас 65 столов. Я веду одну таблицу для отслеживания просмотров объекта (блог / сообщение, форум / ветка, галерея / альбом / изображение и т. Д.), Другую для рекомендаций по объектам и третью таблицу для суммирования операций вставки / обновления в десятке других таблиц.
Одна вещь, которую я делаю немного иначе, - это ведение таблицы entity_type и использование ее идентификатора в столбце object_type (в вашем случае - столбце TABLE). Вы бы хотели сделать то же самое с таблицей event_type.
Уточнение для Аликс - Да, вы ведете справочную таблицу для объектов и справочную таблицу для событий (это будут ваши таблицы измерений).Ваша таблица фактов будет иметь следующие поля:
id
object_id
event_id
event_time
ip_address
Это выглядит довольно разумно, поэтому я просто хотел бросить вызов несколько ваших предположений, чтобы убедиться, что у вас есть конкретные причины для того, что вы делаете.
В моей полностью нормализованной базе данных эта добавляет примерно от 8 до 10 дополнительных таблиц
Это все статистические данные, полученные из существующих данных, не так ли? ( Обновление : хорошо, это не так, поэтому не обращайте внимания на подписку.) Почему бы это не быть просто представлениями или даже материализованными представлениями?
Это может показаться медленной операцией по сбору этой статистики, однако:
I ' мы придумали схему таблицы, которая отделяет очень изменчивые данные от других таблиц, подвергающихся интенсивному чтению
. Я думаю, вы говорите о том, как пользователь (просто для выбора одной таблицы) события, которые были бы довольно непостоянными, отделяются от пользовательских данных. Я согласен с тем, что это должно быть отдельно, но больше потому, что это принципиально разные данные.Что кто-то есть и что кто-то делает - это разные вещи.
Я не думаю, что волатильность так важна. СУБД уже должна позволять вам размещать файл журнала и файл базы данных на разных устройствах, что делает то же самое, и конкуренция не должна быть проблемой при блокировке на уровне строк.
Безотносительно (все еще не так плохо, как EAV)
Я думаю, вам не хватает леса за деревьями, так сказать.
Предикатом для вашей таблицы будет «Идентификатор пользователя с IP-адреса во время DATE EVENTed to TABLE», что кажется разумным, но есть проблемы. (Обновление: хорошо, это что-то вроде этого.)
Вы все еще можете присоединяться, скажем, к пользовательским событиям к пользователям, но вы не можете реализовать ограничение внешнего ключа. Вот почему EAV обычно проблематичен; действительно ли что-то является EAV или нет. Обычно для реализации ограничения в вашей схеме требуется одна или две строки кода, но в вашем приложении это могут быть десятки строк кода, и если одни и те же данные доступны в нескольких местах из нескольких приложений, их можно легко умножить на тысячи строки кода. Итак, как правило, если вы можете предотвратить появление неверных данных с помощью ограничения внешнего ключа, вам гарантировано, что ни одно приложение этого не сделает.
Вы можете подумать, что события не так важны, но, например, показы рекламы - это деньги. Я определенно хотел бы выявлять любые ошибки, связанные с показом рекламы, как можно раньше в процессе разработки.
Дополнительный комментарий
Я могу заметить некоторые предостережения, но пока приложение, связывающееся с базой данных знает, что оно делает, я полагаю, что не должно быть какие-то проблемы.
И с некоторыми оговорками вы можете создать очень успешную систему. При правильной системе ограничений вы можете сказать: «Если какое-либо приложение, вмешивающееся в базу данных, не знает, что делает, СУБД выдаст сообщение об ошибке». Это может потребовать больше времени и денег, чем у вас есть, поэтому что-то более простое, что вы можете иметь, вероятно, лучше, чем что-то более совершенное, чего вы не можете. Такова жизнь.
Я не могу добавить комментарий к ответу Бена, поэтому два момента...
Во-первых, одно дело использовать представления в автономной базе данных OLAP/DSS; совсем другое - использовать их в базе данных транзакций. Люди из High Performance MySQL не рекомендуют использовать представления там, где важна производительность
Что касается целостности данных, я согласен, и это еще одно преимущество использования звезды или снежинки с "событиями" в качестве центральной таблицы фактов (а также использования нескольких таблиц событий, как это делаю я). Но вы не можете разработать схему ссылочной целостности вокруг IP-адресов