База данных лучших практик - PullRequest
7 голосов
/ 27 мая 2010

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

Первоначально я думал, что таблица будет иметь поля user_id и profile_id, поэтому, если пользователь отправляет комментарий, он дает user_id, оставляя profile_id пустым

это правильно, неправильно, есть ли лучший способ?

Ответы [ 5 ]

5 голосов
/ 27 мая 2010

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

Предполагая, что все комментарии связаны с каким-то другим объектом, предположим, что вы извлекаете все комментарии из этого объекта. В предложенном вами проекте извлечение всех комментариев требует выбора только из одной таблицы, что эффективно. Но это извлечение комментариев без извлечения информации о постере каждого комментария. Может быть, вы не хотите показывать это, или они уже кэшированы в памяти.

Но что, если вам нужно было получить информацию о постере при получении комментариев? Затем необходимо объединить две разные таблицы, и теперь результирующий набор записей загрязняется большим количеством значений NULL (для комментария профиля все пользовательские поля будут NULL). Код, который должен анализировать этот набор результатов, также может стать более сложным.

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

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

create table AbstractProfile (ID primary key, type ) -- type can be 'user' or 'profile'
create table User(ProfileID primary key references AbstractProfile , ...)
create table Profile(ProfileID primary key references AbstractProfile , ...)

Тогда в любом месте вашего приложения, где пользователь или профиль могут использоваться взаимозаменяемо, вы можете ссылаться на LoginID.

4 голосов
/ 27 мая 2010

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

user_comments (user_id, comment_id)
profile_comments (profile_id, comment_id)

Тогда вам не нужно иметь пустых столбцов в таблице комментариев. Это также облегчит добавление новых объектов-комментариев-источников в будущем, не касаясь таблицы комментариев.

3 голосов
/ 27 мая 2010

Другой способ решить эту проблему - всегда денормализовать (скопировать) имя комментатора в комментарии, а также сохранить ссылку на комментатор через поле типа и идентификатора. Таким образом, у вас есть единая таблица комментариев, где вы можете быстро искать, сортировать и обрезать. Недостатком является то, что между комментарием и его владельцем нет никаких реальных отношений с ФК.

1 голос
/ 27 мая 2010

В прошлом я использовал централизованную таблицу комментариев и имел поле для таблицы fk_table, на которую она ссылается.

Например:

comments(id,fk_id,fk_table,comment_text)

Таким образом, вы можете использовать запросы UNION для объединения данных из нескольких источников.

SELECT c.comment_text FROM comment c JOIN user u ON u.id=c.fk_id WHERE c.fk_table="user"
UNION ALL
SELECT c.comment_text FROM comment c JOIN profile p ON p.id=c.fk_id WHERE c.fk_table="profile"

Это гарантирует, что вы можете увеличить количество объектов, имеющих комментарии, без создания избыточных таблиц.

0 голосов
/ 28 декабря 2017

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

create table actor_master_table(
  type char(1) not null, /* e.g. 'u' or 'p' for user / profile */
  id varchar(20) not null, /* e.g. 'someuser' or 'someprofile' */
  primary key(type, id)
);

create table user(
  type char(1) not null,
  id varchar(20) not null,
  ...
  check (id = 'u'),
  foreign key (type, id) references actor_master_table(type, id)
);

create table profile(
  type char(1) not null,
  id varchar(20) not null,
  ...
  check (id = 'p'),
  foreign key (type, id) references actor_master_table(type, id)
);

create table comment(
  creator_type char(1) not null,
  creator_id varchar(20) not null,
  comment text not null,
  foreign key(creator_type, creator_id) references actor_master_table(type, id)
);
...