Базы данных: Создание Журнала действий, как обработать различные ссылки?

надеюсь, что Вы все имели с Новым годом.

Так, мой вопрос, что лучший способ состоит в том, чтобы сделать журналом из действий. Позвольте мне объяснить это с примером, предположить, что у нас есть эти объекты:

User

Friend (Пользователь является другом другого Пользователя, многих многим отношения),

Message (Пользователь может передать другого пользователя),

Group (Пользователь может быть в различных группах),

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

Теперь, я хотел сделать журнал, например:

  1. Пользователь (связываются с пользователем) приобрел нового друга, Пользователь B (свяжитесь с пользователем),

  2. Пользователь (связываются с пользователем), B (связываются с пользователем) и C (связываются с пользователем) играл в игру (свяжитесь для игр),

  3. Пользователь C (связываются с пользователем) присоединился, группа D (свяжитесь для группировки),

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

Я знаю два способа сделать это, но у них всех есть одна или несколько проблем:

  1. При входе действия я непосредственно храню чистый текст, который я хочу (т.е.: только 1 символьное поле, которое сохранило бы 'Пользователя C, присоединилось к группе'). Но, существует проблема этот путь, этот текст должен быть переведен на другие языки, и у меня не может быть поля для каждого языка.

  2. Наличие основной таблицы log, который каждый располагает в ряд, представляют действие журнала и код, таким образом, я знаю, которым действие состоит в том что, т.е.: пользователь присоединился к группе, x пользователи играл в игру. У меня затем есть другая таблица для каждого из необходимых типов внешнего ключа, таким образом, я имел бы log_user, log_group и log_game Например, log_user с полевой ссылкой log и другая ссылка user. Таким образом, у меня могут быть многочисленные пользователи для того же действия журнала. Проблемы: довольно сложный и мог привести к существенным издержкам как в зависимости от действия журнала, которое я должен буду запросить к нескольким таблицам. Это корректно, это было бы слишком интенсивно CPU?

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

Править: Я решил запустить щедрость, поскольку я не действительно доволен ответами, которые я получил. Сделает любые разъяснения в случае необходимости. Спасибо

Я хочу что-то очень похожее на facebook/orkut/social сети "друг обновления". Это будет отображено пользователям.

5
задан Clash 5 January 2010 в 18:59
поделиться

4 ответа

Ниже приведены, как я это сделал. У меня есть еще несколько комментариев внизу после того, как вы видели схему.

Журнал

Логид - Уникальный идентификатор журнала

Время - Дата / время события

LogType - String или ID

(Боковой комментарий, я бы пошел с идентификатором здесь, чтобы вы могли использовать сообщение Таблица показана ниже, но если вы хотите быстрое n Starthy, вы можете просто только уникальную строку для каждого времени журнала (например, «Началась игра», - отправлено сообщение «, и т. Д.)

LOGACTOR

Логида - Внешняя клавиша

LOGACTORTYPE - String или ID (как указано выше, если удостоверение личности вам понадобится таблица поиска)

LOGACTORID - это уникальный идентификатор для таблицы для типа, например, пользователя, группа, группа, игра

- это упорядочение Актеры.

logmessage

logtype - Exernal Key

Сообщение - Long String (varchar (max)?)

Язык - Строка (5) Итак, вы можете выбрать разных языков, например, «US-EN»

Пример данных (Используя ваши 3 примера)

Журнал

ID  Time   LogType 
1   1/1/10 1
2   1/1/10 2
3   1/1/10 3

LOGACTOR

LogID LogActorType LogActorID Sequence
1     User         1          1
1     User         2          2
2     User         1          1
2     User         2          2
2     User         2          3
2     Game         1          4
3     User         3          1
3     Group        1          2

LogMessage

LogType Message 
1       {0} Made a new friend {1}
2       {0}, {1}, {2} played a game ({3})
3       {0} joined a group ({1})

User

ID Name
1  User A
2  User B
3  User C

Игра

ID Name
1  Name of game

Группа

ID Name
1  Name of group

Так вот приятные вещи об этом дизайне.

  • Очень легко расширить

  • это обрабатывает многоязычные проблемы независимо от актеров

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

Некоторые плохие вещи об этом.

  • Вы должны сделать какую-то сложную обработку для чтения сообщений.

  • Вы не можете просто посмотреть на БД и посмотреть, что произошло.

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

Дайте мне знать, если у вас есть вопросы.

Обновление - некоторые примеры запросов

Все мои примеры находятся в SQLSERVER 2005+, дайте мне знать, если есть другая версия, которую вы хотите, чтобы я целевым.

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

a)

SELECT 
  LogId,
  COLLESCE(U.Name,Ga.Name,Go.Name) AS Name,
  Sequence
FROM LogActor A
LEFT JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
LEFT JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
LEFT JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
ORDER BY LogID, Sequence

b)

SELECT 
  LogId,
  U.Name AS Name,
  Sequence
FROM LogActor A
INNER JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
UNION ALL
SELECT 
  LogId,
  Ga.Name AS Name,
  Sequence
FROM LogActor A
INNER JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
UNION ALL
SELECT 
  LogId,
  Go.Name AS Name,
  Sequence
FROM LogActor A
INNER JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
ORDER BY LogID, Sequence

В общем я думаю, что A) лучше чем B) Например, если вы отсутствуете, если вы не пропустите акт артистики A), будет включать его (с нулевым именем). Однако B) легче поддерживать (потому что профсоюз все заявления делают его более модульным.) Есть другие способы сделать это (например, CTE, Views и т. Д.). Я склонен делать это, как б) и от того, что я видел, что, кажется, по крайней мере, стандартная практика, если не лучшая практика.

Итак, последние 10 элементов в журнале будут выглядеть что-то подобное:

SELECT 
  LogId,
  M.Message,
  COLLESCE(U.Name,Ga.Name,Go.Name) AS Name,
  Time,
  A.Sequence
FROM Log
LEFT JOIN LogActor A ON Log.LogID = A.LogID
LEFT JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
LEFT JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
LEFT JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
LEFT JOIN LogMessage M ON Log.LogType = M.LogMessage
WHERE LogID IN (SELECT Top 10 LogID FROM Log ORDER BY Date DESC)
ORDER BY Date, LogID, A.Sequence

NB - как вы можете видеть, легче выбирать все элементы журнала с даты, чем последний X, потому что нам нужен (вероятно, Очень быстрый) подпросиер для этого.

3
ответ дан 14 December 2019 в 08:52
поделиться

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

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

Например, "Пользователь A (ссылка на пользователя), B (ссылка на пользователя) и C (ссылка на пользователя) играл в игру (ссылка на игру)" было бы

<a href="/users/showuser.php?id=2341">User A</a>
, <a href="/users/showuser.php?id=311">User B</a>
, and <a href="/users/showuser.php?id=89">User C</a>
played a game of <a href="/games/gameoverview.php?id=3">Chess</a>.
1
ответ дан 14 December 2019 в 08:52
поделиться
  1. Сохраните его простым и расширяемым
  2. Не позволяйте накладным расходам на перевод влиять на производительность, перевод необходимо выполнять только в целях вывода.

Предложение:

 LogId       DateTime   Action   Role  Entity

 e.g.

 30303     1/1/10    43        Sender   John
 30303     1/1/10    43        Receiver Sam
 30304     1/1/10    44        Game      game43
 30304     1/1/10    44        Player    Sue
 30304     1/1/10    44        Player    Mike

(В приведенной выше таблице "Сообщение", "Отправитель", "Джон", "игра43" и т.д. будут не текстом, а инородными ключами либо в таблице действий, ролей, либо в таблице сущностей. Я написал ключи для "Действия", но не для "Роли" или "Сущности", но они также будут ключами.

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

 Action Table

 Id    ActionKey   Text      Language
 1     43          JoinGame  English
 2     43          Jeu       French
 3     44          Message   English
 ...
 ...

 Role Table
 Id   RoleKey  Text  Language
 1    1        Sender   English
 2    1        Sendeur  French        (I don't know french :)
 ....

 Entity Table
 EntityKey   Text
 1           Sam
 2           game43
 3           Sam

Обратите внимание, что в таблице сущностей, 2 или более записей могут иметь то же самое текстовое представление, так как может быть более 1 пользователя по имени Sam. Если вы хотите представить различную, ортогональную информацию о каждой сущности, то вы можете включить EntityKey в соответствующую таблицу, например,

Person Table
Id    EntityKey   FirstName  LastName ....
1      1          Sam         Johnson

Game Instance Table
Id    EntityKey   GameType  
1     2           444

Game Table
Id   Name   MaxPlayers ...
444  Quake    10

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

1
ответ дан 14 December 2019 в 08:52
поделиться

Мой ответ на Какая стратегия лучше для хранения данных журнала в базе данных? :

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

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

Итак, ответ - оба.

Изменить : чтобы реализовать его чисто с ссылочной целостностью и обладать всей гибкостью, я предлагаю создать дублирующую таблицу контрольного журнала для всех CRUD для каждой таблицы, даже если она «тяжелая». В любом случае бизнес-правила более изменчивы по сравнению со структурами данных, поэтому, сохраняя логику журнала в коде / запросе, вы сохраняете гибкость. Например, предположим, что вы решили не отслеживать, когда пользователи покинули группу. Позже клиенты спросили, что очень важно отслеживать информацию. Все, что вам нужно сделать сейчас, это изменить запрос так, чтобы удаление записи user_group было частью результата.

2
ответ дан 14 December 2019 в 08:52
поделиться
Другие вопросы по тегам:

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