2014-10-17 113 views
1

我一直在制作一个显示评分阶梯的网站,它处理所有玩家比赛的比赛。附加链接

我现在所拥有的是下表,但是当我想要选择一个玩家的所有匹配时,我必须包含“或”语句,并且对于所有具有玩家名字的列都有索引。所以我设计了一种新方法。

[当前方法]

aoe3_sp_games表

信息:保持打过的所有比赛和与它有关的球员。

Column Type Null Default 
game_id char(36) No   
map varchar(30) No   
date_time int(11) No   
length float No   
player_count tinyint(4) No   
t1_p1 varchar(16) No   
t1_p2 varchar(16) No   
t1_p3 varchar(16) No   
t1_p4 varchar(16) No   
t2_p1 varchar(16) No   
t2_p2 varchar(16) No   
t2_p3 varchar(16) No   
t2_p4 varchar(16) No   
t1_p1_rating smallint(4) No   
t1_p2_rating smallint(4) No   
t1_p3_rating smallint(4) No   
t1_p4_rating smallint(4) No   
t2_p1_rating smallint(4) No   
t2_p2_rating smallint(4) No   
t2_p3_rating smallint(4) No   
t2_p4_rating smallint(4) No   
t1_p1_pr float(6,2) No   
t1_p2_pr float(6,2) No   
t1_p3_pr float(6,2) No   
t1_p4_pr float(6,2) No   
t2_p1_pr float(6,2) No   
t2_p2_pr float(6,2) No   
t2_p3_pr float(6,2) No   
t2_p4_pr float(6,2) No   
t1_p1_civ char(2) No   
t1_p2_civ char(2) No   
t1_p3_civ char(2) No   
t1_p4_civ char(2) No   
t2_p1_civ char(2) No   
t2_p2_civ char(2) No   
t2_p3_civ char(2) No   
t2_p4_civ char(2) No 

[新方法]

aoe3_sp_matches表

信息:包含所有比赛打过。

Column Type Null Default 
match_id int(10) No   
match_guid char(36) No   
map varchar(30) No   
date_time int(11) No   
length float No   
player_count tinyint(4) No 

aoe3_sp_match_players表

信息:容纳了与从#Matches_table比赛的球员。

Column Type Null Default Links to 
match_id int(10) No  aoe3_sp_matches -> match_id  
player_id int(10) No  eso_players -> player_id   
team tinyint(4) No    
player_name varchar(16) No    
player_rating smallint(4) No    
player_pr float(6,2) Yes NULL    
player_civ char(2) No 

我需要的是获得玩家使用#Match_Players_table玩过的所有匹配。 然后将比赛ID加入参与比赛的球员。

任何比赛最多只能有8名选手(4vs4)和至少2名(1vs1)选手。

我正在使用Player 1570进行测试,因为他看起来非常适合没有太多比赛的情况。

我读过的地方不要使用不超过2个连接,否则它可能会降低性能。 我的网站处理大约5000〜3天的比赛和17000〜行的玩家,这些数字是基于新方法。

我的mysql版本是:5.1.61。

我的网站http://exciple.com/forum/player.php?n=yosimasa&s=m

SQL小提琴http://sqlfiddle.com/#!2/0b2245/3


结果类型一个

基本上将所有日e球员属于那一场比赛的信息,就像方法一一样。我确实试图获得像这样的结果,但是我在加入多于一行的连接时遇到困难。我知道这需要很多连接,所以不是理想的方式。

game_id map date_time length player_count t1_p1 t1_p2 t1_p3 t1_p4 t2_p1 t2_p2 t2_p3 t2_p4 t1_p1_rating t1_p2_rating t1_p3_rating t1_p4_rating t2_p1_rating t2_p2_rating t2_p3_rating t2_p4_rating t1_p1_pr t1_p2_pr t1_p3_pr t1_p4_pr t2_p1_pr t2_p2_pr t2_p3_pr t2_p4_pr t1_p1_civ t1_p2_civ t1_p3_civ t1_p4_civ t2_p1_civ t2_p2_civ t2_p3_civ t2_p4_civ 
    43f9499f-870d-47c0-8a05-47554e349698 great plains 1413510540 1451 4 greenandugly Jomp17   Armykid913 FUHAHAHA   1616 1616 0 0 1584 1571 0 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 FR OT   OT BR 

结果两型

所以我一直在使用查询瞎搞,这里是我得到了什么至今。

执行两个查询

[大游戏]

SELECT aoe3_sp_matches.* FROM aoe3_sp_matches 
right JOIN `aoe3_sp_match_players` 
ON `aoe3_sp_match_players`.`match_id`=`aoe3_sp_matches`.`match_id` 
WHERE player_id = 1570 

返回播放器1570的所有比赛能正常工作。

[第二个用于比赛的选手]

SELECT aoe3_sp_match_players.* FROM aoe3_sp_match_players 
right JOIN `aoe3_sp_matches` 
ON `aoe3_sp_match_players`.`match_id`=`aoe3_sp_matches`.`match_id` 
WHERE aoe3_sp_match_players.player_id = 1570 

从aoe3_sp_match_players返回数据,与where子句满足。不返回所有玩家,但只返回where子句中的玩家。

SELECT aoe3_sp_match_players.* FROM aoe3_sp_match_players 
WHERE aoe3_sp_match_players.match_id in 
    (SELECT aoe3_sp_match_players.match_id 
     FROM aoe3_sp_match_players 
     WHERE player_id = 1570) 

我设法获取数据我想要的方式,但使用子查询,这是慢于我的数据库,而不是一个surprize那里的联接。

编辑:我找到一种方式来获得使用在外面连接结果两型的第二部分,它是一样快的where子句加盟之前放置。

Select 
    aoe3_sp_match_players.match_id, 
    aoe3_sp_match_players.team, 
    aoe3_sp_match_players.player_name, 
    aoe3_sp_match_players.player_rating, 
    aoe3_sp_match_players.player_pr, 
    aoe3_sp_match_players.player_civ 
From 
    (Select 
    aoe3_sp_match_players.match_id 
    From 
    aoe3_sp_match_players 
    Where 
    aoe3_sp_match_players.player_id = 1570 
    Limit 30) aoe3_sp_matches Left Join 
    aoe3_sp_match_players On aoe3_sp_match_players.match_id = 
    aoe3_sp_matches.match_id 
Order By 
    aoe3_sp_match_players.match_id Desc 

你认为获得结果的最好方法是什么?

+0

你有没有写过一个工作'JOIN'? – 2014-10-17 02:18:42

+0

是的一个基本的:SELECT'aoe3_sp_civs_overall'.'player_id','aoe3_sp_civs_overall'.'BR_used','aoe3_sp_overall'.'rating' FROM'aoe3_sp_overall' INNER JOIN'aoe3_sp_civs_overall' ON'aoe3_sp_civs_overall'.'player_id' ='aoe3_sp_overall'.'player_id' ORDER BY'aoe3_sp_overall'.'rating' DESC LIMIT 0,30; – Antonio 2014-10-17 02:21:20

+0

显然最好使用规范化表格。你还没有在那里。您需要在**球员**中只有关于球员本身的信息,然后创建一个单独的“*链接*”表** PlayersInMatches **您将与match_id匹配的球员匹配项(无法使用盘)'player_id'。所以三个表格需要两个简单的'INNER JOIN'。 – 2014-10-17 02:30:09

回答

0

此设置存在问题。你的新方法肯定比上一个更好,但它仍然需要一些解决方法。尽管如此,你仍然处于正确的轨道。

对于每场比赛允许的球员数量是否有限制?看起来你的旧方法每场比赛最多可容纳4名球员。在你的新方法中,每场比赛你可以有任意数量的球员,这可能是也可能不是你想要的。

只有在您的应用程序中强制执行最多四名玩家才能分享比赛时,您所期望的结果才能实现。但这不是所期望的,因为您的数据完整性现在取决于应用程序层而不仅仅是数据库。

不考虑这些事情,我所提到的,你可以做这样的事情:

SELECT 
    game.match_id, 
    game.match_guid, 
    game.map, 
    game.date_time, 
    game.length, 
    game.player_count, 

    team1_player1.player_name, 
    team1_player1.player_rating, 
    team1_player1.player_pr, 
    team1_player1.player_civ, 
    team1_player2.player_name, 
    team1_player2.player_rating, 
    team1_player2.player_pr, 
    team1_player2.player_civ, 
    team1_player3.player_name, 
    team1_player3.player_rating, 
    team1_player3.player_pr, 
    team1_player3.player_civ, 
    team1_player4.player_name, 
    team1_player4.player_rating, 
    team1_player4.player_pr, 
    team1_player4.player_civ, 
    team2_player1.player_name, 
    team2_player1.player_rating, 
    team2_player1.player_pr, 
    team2_player1.player_civ, 
    team2_player2.player_name, 
    team2_player2.player_rating, 
    team2_player2.player_pr, 
    team2_player2.player_civ, 
    team2_player3.player_name, 
    team2_player3.player_rating, 
    team2_player3.player_pr, 
    team2_player3.player_civ, 
    team2_player4.player_name, 
    team2_player4.player_rating, 
    team2_player4.player_pr, 
    team2_player4.player_civ 
FROM 
    matches_table as game 
    LEFT JOIN match_players as team1_player1 ON game.match_id = team1_player1.match_id and team1_player1.player_id = 1 
    LEFT JOIN match_players as team1_player2 ON game.match_id = team1_player2.match_id and team1_player1.player_id = 2 
    LEFT JOIN match_players as team1_player3 ON game.match_id = team1_player3.match_id and team1_player1.player_id = 3 
    LEFT JOIN match_players as team1_player4 ON game.match_id = team1_player4.match_id and team1_player1.player_id = 4 
    LEFT JOIN match_players as team2_player1 ON game.match_id = team2_player1.match_id and team1_player1.player_id = 5 
    LEFT JOIN match_players as team2_player2 ON game.match_id = team2_player2.match_id and team1_player1.player_id = 6 
    LEFT JOIN match_players as team2_player3 ON game.match_id = team2_player3.match_id and team1_player1.player_id = 7 
    LEFT JOIN match_players as team2_player4 ON game.match_id = team2_player4.match_id and team1_player1.player_id = 8 

你必须知道的玩家的ID前面。此外,一名球员只能附加一场比赛。这个价值将不得不为新的比赛而改变,我们也不会记录任何以前比赛中的球员的历史。这是为了说明它可以完成,并且它可以得到多么丑陋。我不建议以这种方式进行。

但请注意,您可以多次加入同一张表。这可能非常有用,因为您需要将来自许多记录的信息精简为一个。


SOLUTION:

你可以有一个游戏桌,玩家一张桌子和创造相匹配的第三个表:

游戏

game_id 
map 
//other columns with info about this map. you could also name the table maps 

球员

player_id 
player_name 
player_pr 
player_civ 

匹配

match_id 
map 
date_time 
team1_player1 
team1_player2 
team2_player1 
team2_player2 

这最后的表包含玩家的ID。输出看起来是这样的:

match_id map    team1_player1 team1_player2 team2_player1 team2_player2 
1   great plains  0001   0002   0003   0004 

您还可以使用用户名作为标识,只是可以肯定他们是唯一的(主键)

产生的SQL查询将是这样的:

SELECT 
    games.map, 
    matches.match_id, 
    matches.date_time, 

    team1_player1.player_name, 
    team1_player1.player_rating, 
    team1_player1.player_pr, 
    team1_player1.player_civ, 
    team1_player2.player_name, 
    team1_player2.player_rating, 
    team1_player2.player_pr, 
    team1_player2.player_civ, 
    team1_player3.player_name, 
    team1_player3.player_rating, 
    team1_player3.player_pr, 
    team1_player3.player_civ, 
    team1_player4.player_name, 
    team1_player4.player_rating, 
    team1_player4.player_pr, 
    team1_player4.player_civ, 
    team2_player1.player_name, 
    team2_player1.player_rating, 
    team2_player1.player_pr, 
    team2_player1.player_civ, 
    team2_player2.player_name, 
    team2_player2.player_rating, 
    team2_player2.player_pr, 
    team2_player2.player_civ, 
    team2_player3.player_name, 
    team2_player3.player_rating, 
    team2_player3.player_pr, 
    team2_player3.player_civ, 
    team2_player4.player_name, 
    team2_player4.player_rating, 
    team2_player4.player_pr, 
    team2_player4.player_civ 
FROM 
    games 
    INNER JOIN matches ON matches.map = games.map 
    INNER JOIN match_players as team1_player1 ON team1_player1.player_id = matches.team1_player1 
    INNER JOIN match_players as team1_player2 ON team1_player1.player_id = matches.team1_player2 
    INNER JOIN match_players as team1_player3 ON team1_player1.player_id = matches.team1_player3 
    INNER JOIN match_players as team1_player4 ON team1_player1.player_id = matches.team1_player4 
    INNER JOIN match_players as team2_player1 ON team1_player1.player_id = matches.team2_player1 
    INNER JOIN match_players as team2_player2 ON team1_player1.player_id = matches.team2_player2 
    INNER JOIN match_players as team2_player3 ON team1_player1.player_id = matches.team2_player3 
    INNER JOIN match_players as team2_player4 ON team1_player1.player_id = matches.team2_player4 

通过这种方法,您的球员表只包含关于球员的信息,而不包含任何关于比赛的信息。您保留了球员所参加的每场比赛的历史记录,并且您还可以将地图和与比赛相关的其他信息与比赛本身分开。火柴表只将所有东西连接在一起。此外,玩家数量限制还回到了数据库,并且与应用程序无关。

希望它有帮助。

+0

而当你决定拥有每场比赛4名球员的最高限额将会导致您的业务受到影响,您需要重新设计数据库。当然,你需要在应用程序中强制执行限制,有些游戏可能有2个其他限制,并且将来有些游戏可能没有限制......所以不要以有限的方式设计数据库。 – 2014-10-17 05:31:50

+0

嗯,是的,但我的回答是针对这个人问的已经和想要的。这不是我会怎么做,但它回答了这个问题。他希望将结果排成一行。 – Vic 2014-10-17 05:38:55