Структура базы данных для игры 2 на 2

10

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

Поскольку мы регулярно меняем команды, я придумал таблицы players, teamsи gamesв играх было две команды (team1 и team2), а команды состоят из двух игроков (player1 и player2).

Это вызывает довольно много проблем - например, если я выберу двух игроков (назовем их A и B ) для совместной игры, я должен проверить, существует ли уже команда, в которой Player1 - A, а Player2 - B или Player1 - B и Player2. это.

Столбцы gamesи winsприсутствуют как в playersтаблице, так и в teamsтаблице - но это потому, что я хочу увидеть, сколько игр выиграют игроки, а также насколько совместим игрок в разных командах (как часто игрок выигрывает, когда объединяется с другой конкретный игрок).

  1. Рейтинговое табло (вероятно, я собираюсь использовать систему рейтинга Эло )
  2. Страница статистики для каждого игрока с рейтингом, победами, играми, статистикой последних игр и с какими игроками он наиболее совместим.

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

Дизайн базы данных

Даниил
источник
Я думаю, что это очень хороший вопрос. Хотелось бы увидеть вашу текущую структуру БД в диаграмме в вопросе. Не все знают Laravel's Schema Builder. Варианты использования также могут быть лучше разработаны, чтобы мы понимали ваши реальные потребности.
Candied_Orange
Большое спасибо @CandiedOrange - я добавил диаграмму структуры БД и добавлю больше вариантов использования :)
Даниэль
Хорошее обновление. Буду ли я прав, предполагая, что каждый игрок будет играть только в одной команде одновременно и только в одной игре за раз? Кроме того, что игроки уходят и возвращаются в старые команды без сброса информации для этой команды?
candied_orange
@CandiedOrange В основном, когда мы хотим сыграть в игру, мы находим 4 игроков (из общего числа ~ 12 игроков) и случайным образом объединяем их в команды по 2 человека.
Даниэль
Я не могу сказать, было ли это да или нет. Я пытаюсь понять, как время влияет на ваш дизайн.
candied_orange

Ответы:

2

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

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

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

Что касается нормализации, рассмотрите возможность отделения сущностей от результатов, полученных с помощью team_resultтаблицы для отслеживания всех результатов для данной группы. Немного более экстремальная нормализация также потребовала бы player_rating_histтаблицы, содержащей все изменения рейтинга для игрока. Их текущий рейтинг просто тот, с самой последней датой. Представление игрока также может быть использовано, чтобы содержать самые последние значения для удобства запросов.

Предлагаемая схема (извините, без схемы):

player
    id
    name
    created_on
    updated_on

player_rating_hist
    player_id (FK)
    rating
    rating_date

team
    id
    player1_id (FK)
    player2_id (FK)
    created_on
    updated_on

game
    id
    team1_id (FK)
    team2_id (FK)

team_game
    team_id (FK)
    game_id (FK)
    result
    score
    rating_change

team_rating_hist
    team_id (FK)
    rating
    rating_date

Запросы:

--Results for the game, should only ever be two rows for any given game
SELECT * FROM team_game WHERE game_id = 101

--All results for a team
SELECT * FROM team_game WHERE team_id = 123456 

Эта структура позволяет отделить «базовые» объекты (игроков и команды) от «контента», возникающего в результате работы системы с течением времени, и означает, что вы не постоянно обновляете одну из базовых таблиц с текущим рейтингом, # выигрышей и т. д. Это производные значения, которые следует извлекать, получая самые последние оценки, среднюю оценку COUNTвыигрышей или проигрышей и т. д. Если система стала достаточно большой, вы можете рассмотреть возможность извлечения таких агрегированных данных в отдельный «склад» (даже если это был просто отдельный набор таблиц в одной и той же БД) для упрощения аналитики.

Dan1701
источник