Эффективная структура таблиц MySQL для рейтинговой системы - PullRequest
3 голосов
/ 07 марта 2009

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

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

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

SELECT avg(vote) FROM votes WHERE uid = $uid AND gid = $gid;    
SELECT count(uid) FROM votes WHERE uid = $uid AND gid = $gid;

CREATE TABLE IF NOT EXISTS `games` (
  `id` int(8) NOT NULL auto_increment,
  `title` varchar(50) NOT NULL,
  PRIMARY KEY  (`id`)
) AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(8) NOT NULL auto_increment,
  `username` varchar(20) NOT NULL,
  PRIMARY KEY  (`id`)
) AUTO_INCREMENT=1 ;


CREATE TABLE IF NOT EXISTS `votes` (
  `uid` int(8) NOT NULL,
  `gid` int(8) NOT NULL,
  `vote` int(1) NOT NULL,
  KEY `uid` (`uid`,`gid`)
) ;

Ответы [ 5 ]

6 голосов
/ 09 марта 2009

среднее количество голосов за игру: SELECT avg(vote) FROM votes WHERE gid = $gid;

количество голосов за игру: SELECT count(uid) FROM votes WHERE gid = $gid;

Поскольку у вас не будет идентификаторов пользователей или игр, меньших 0, вы можете сделать их целыми числами без знака (int(8) unsigned NOT NULL).

Если вы хотите, чтобы пользователь мог сделать только один голос за игру, то создайте первичный ключ над uid и gid в таблице votes вместо обычного индекса.

CREATE TABLE IF NOT EXISTS `votes` (
  `uid` int(8) unsigned NOT NULL,
  `gid` int(8) unsigned NOT NULL,
  `vote` int(1) NOT NULL,
  PRIMARY KEY (`gid`, `uid`)
) ;

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

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

2 голосов
/ 07 марта 2009

Хорошо выглядит.

Я бы использовал users_id & games_id вместо gid и uid, который звучит как глобальный идентификатор и уникальный идентификатор

1 голос
/ 09 марта 2009

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

Напишите скрипт, который генерирует 100 000 игр, 50 000 пользователей и миллион голосов. Может быть немного чрезмерно, но если ваши запросы не занимают часы с таким количеством элементов, это никогда не будет проблемой

0 голосов
/ 03 июля 2009

Вы также можете добавить столбец voted_on (DATETIME). Таким образом, вы можете, скажем, увидеть тенденцию игры за определенный промежуток времени, или просто в случае, если когда-нибудь произойдет спам при голосовании, вы сможете точно удалить нежелательные голоса.

0 голосов
/ 07 марта 2009

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

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

...