2015-07-11 79 views
1

我有这样的表建立一个数据库的游戏结果:SQL查询性能

Table Players 
id ... name 
1 .... Alice 
2 .... Bob 
3 .... Charlie 
    ... etc 
Table Games 
Player1 Player2 myscore oppscore result 
    1 ... 3 .... 25 ... 18 .... W 
    3 ... 2 .... 15 ... 20 .... L 
    2 ... 1 .... 17 ... 17 .... T 

myScore的指PLAYER1,oppscore指Player2

我想返回一个玩家的最频繁的查询对手,以及他们之间的输赢记录。 (我与每个对手第二个查询的输赢记录。)

所以我用这个:

SELECT count(*) p2.name "Opponent", 
FROM games, players p1, players p2 
WHERE p1.name = ? 
AND games.gametype = ? 
AND games.player1 = p1.id 
AND games.player2 = p2.id 
GROUP BY player2, gametype 
ORDER BY count(*) DESC 

为了拿起所有游戏(不管是谁PLAYER1 和谁是player2)我店每场比赛两次: 即我真有:

Player1 Player2 myscore oppscore result 
    1 ... 3 .... 25 ... 18 .... W 
    3 ... 1 .... 18 ... 25 .... L 
    3 ... 2 .... 15 ... 20 .... L 
    2 ... 3 .... 20 ... 15 .... W 
    2 ... 1 .... 17 ... 17 .... T 
    1 ... 2 .... 17 ... 17 .... T 

我想消除数据的冗余,从而 减少一半的数据库大小。

我试过了(其中g1是类似游戏的表格,但是删除了冗余行的 )。

create view gv as 
    select * from g1 
union 
    select 
    player2 player1, 
    player1 player2, 
    (case when result = 'T' then 'T' 
     when result = 'W' then 'L' 
     when result = 'L' then 'W' 
      end) result, 
    oppscore myscore, 
    myscore oppscore 
    from g1 

然后做我的查询反对gv而不是反对游戏。

其中的工作...除了它需要(基于一个例子), 超过10倍(游戏0.10秒,vs 1.4秒 为gv)。

有没有更好的方法来做到这一点?

+0

您可以发布您针对该视图运行的查询吗? –

+0

这是相同的查询 - 只是使用视图名称(gv)而不是表名(游戏)。 –

回答

1

我认为视为方便,而工会则慢。把它们加在一起,你会变得很慢。好吧,超过泛化。

你能表现什么样的表现?

非规范化(冗余和翻转在你的情况下)数据肯定有它的好处,即速度在浪费空间的代价。这是一个杂耍的行为。

您的观点有一点是,它没有过滤器,它做了两个表扫描的联合。随着分数的增加,情况变得更糟。你不使用索引。

你真的需要查看所有的数据,当你可以有一个存储过程与IN参数集中在indexed玩家ID与自我加入或类似的?

索引可以成为你最好的朋友。通过运行查询mysql explain可以提供帮助。

无论如何,我希望这是有帮助的一些小方法。

+0

另外两个复合索引(player1,player2)和(player2,player1)可以产生良好的结果 – Drew

+0

当我创建新的非冗余表进行测试时,我已经忘记了索引,但即使在我将它们添加到两个(player1,player2 )和(player2,player1)的时间保持不变。 –

+0

您的查询在运行时使用的是什么索引 – Drew

1

在你的视图中使用union all而不是union。它的速度要快得多,因为union不会检查重复的行,而union通常会检查重复的行。

+0

感谢您的提示 - 联盟所有似乎是快20%左右。使用UNION创建使用的临时表(65,50,55,49,59 - 平均56毫秒)和UNION ALL(45,44,48,44,49 - 平均46毫秒)重复试验完全相同的查询。 –

+0

更多速度。不要创建视图。不要只把结果拉到分数上。尝试在第一个查询中从g1过滤player1并在第二个查询中将player2过滤到union之前,然后将case语句应用于结果表。案例陈述可能已经强制全表扫描。 –

+0

对 - 我已经取消了视图,而是使用TEMPORARY TABLE,只有player1的行和player2上的索引...它现在运行速度非常快。我认为这是造成桌面扫描的视图本身。 –