Эффективная структура таблицы MySQL для рейтинговой системы
Этот пост является продолжением ответа на этот вопрос: Лучший способ хранения списка идентификаторов пользователей.
Я взял клитус и Мехрдад Афшари в эпическом совете по использованию нормализованного подхода к базе данных. Правильно ли настроены следующие таблицы для правильной оптимизации? Я новичок в эффективности 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`)
) ;
Ответы
Ответ 1
средний голос (ов) за игру: 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
Выглядит хорошо.
Я бы использовал users_id и games_id вместо gid и uid, который звучит как глобальный id и уникальный id
Ответ 3
Что бы вы ни делали, убедитесь, что вы проверили его с помощью большого набора данных (даже если вы не планируете иметь огромное количество пользователей)
Напишите script, который генерирует 100 000 игр, 50 000 пользователей и миллион голосов. Может быть немного чрезмерным, но если ваши запросы не занимают часы с таким количеством элементов, это никогда не будет проблемой.
Ответ 4
Выглядит хорошо. Не забывайте индексы и внешние ключи. По моему опыту большинство проблем не возникает из-за не-продуманных проектов, а из-за отсутствия индексов и внешних ключей.
Кроме того, в отношении выбора механизма хранения я еще не вижу причины (в достаточно сложном/размерном приложении) не использовать innodb, а не только из-за транзакционной семантики.
Ответ 5
вы можете добавить столбец voted_on
(DATETIME). Таким образом, вы могли бы, скажем, увидеть тенденцию игры в определенный промежуток времени, или на всякий случай когда-нибудь проголосовал за спам, вы можете точно удалить нежелательные голоса.
Ответ 6
Тогда как сортировать игры по рейтингу? @https://stackoverflow.com/users/75425/uwe-mesecke uwe-mesecke