用于评级系统的高效MySQL表结构

时间:2009-03-07 01:00:07

标签: php mysql optimization performance project-planning

这篇文章是对这个已回答问题的跟进:Best method for storing a list of user IDs

我采用了cletus和Mehrdad Afshari关于使用规范化数据库方法的史诗建议。是否正确设置了以下表格以进行适当的优化?我对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 个答案:

答案 0 :(得分:6)

游戏的平均投票:SELECT avg(vote) FROM votes WHERE gid = $gid;

游戏的投票数:SELECT count(uid) FROM votes WHERE gid = $gid;

由于你没有任何比0更小的用户或游戏ID,你可以使它们成为无符号整数(int(8) unsigned NOT NULL)。

如果您想强制用户只能对游戏进行一次投票,那么在uid表格中创建一个主键gidvotes而不只是正常指数。

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或其他方式实现缓存系统。

答案 1 :(得分:2)

看起来不错。

我会使用users_id& games_id而不是gid和uid,听起来像全球ID和唯一ID

答案 2 :(得分:1)

无论您最终做什么,请确保使用大型数据集进行测试(即使您不打算拥有大量用户)

编写一个可生成100,000个游戏,50,000个用户和100万个投票的脚本。可能略微过分,但如果您的查询不需要花费数小时来处理这些项目,那么它将永远不会成为问题

答案 3 :(得分:0)

到目前为止看起来不错。不要忘记索引和外键。根据我的经验,大多数问题不是来自不那么经过深思熟虑的设计,而是来自缺乏指数和外键。

此外,关于存储引擎选择,我还没有看到不使用innodb的原因(在一个相当复杂/大小的应用程序中),而不仅仅是因为事务语义。

答案 4 :(得分:0)

您可能还想添加voted_on(DATETIME)列。这样,您可以,比如说,在某个时间段内看到游戏的趋势,或者只是在某天发生投票垃圾邮件的情况下,您可以准确地删除不需要的投票。