Php 如何优化这个MySQL查询?

Php 如何优化这个MySQL查询?,php,sql,optimization,mysql,Php,Sql,Optimization,Mysql,我在一个PHP脚本中使用下面的MySQL查询,这个数据库包含超过3700000000(是的,37000000)行。我知道这是一个非常耗费资源的查询,运行这个查询需要很长时间。有人知道我如何优化查询或以另一种更快的方式获取信息吗 表格信息: games | longint, unsigned, Primary Key win | bit(1) loss | bit(1) 提前感谢您的帮助 我能提出的唯一建议是使用一个表来预先计算每个游戏的所有计数和总和,并在表游戏更改时使用触发器进行更新。我

我在一个PHP脚本中使用下面的MySQL查询,这个数据库包含超过3700000000(是的,37000000)行。我知道这是一个非常耗费资源的查询,运行这个查询需要很长时间。有人知道我如何优化查询或以另一种更快的方式获取信息吗

表格信息:

games | longint, unsigned, Primary Key win | bit(1) loss | bit(1)
提前感谢您的帮助

我能提出的唯一建议是使用一个表来预先计算每个游戏的所有计数和总和,并在表游戏更改时使用触发器进行更新。

我会尝试从查询开始,或者。

如果你读得太多,考虑在你通常查询的数据上保持并保持一个聚合表。

< P>听起来像你可以对它进行去重化和创建一个“移动”表,记录每一个“移动”的统计数据,而不仅仅是每个“游戏”。

你可以通过牺牲存储空间或OnService存储空间来获得“速度”,但是性能更差。由于您的问题是速度,因此需要进行一些预先计算。是的,对查询进行了一些分析

顺便说一句,对于OLTP(实时服务于实际事务)和DW(分析大量数据),“大公司”过去有不同的配置(不同的硬件和设置)。

mid()函数正是扼杀此查询的原因。 MySQL必须在内存中创建一个临时表来处理mid()函数,并对该表进行文件排序,因为GROUPBY

我假设$game是一种游戏类型。(跳棋、国际象棋、井字游戏)

我会为这种游戏再挂一张桌子。这使您的团队可以使用更快的索引

我建议如下:

[game]
game bigint unsigned
win bit
loss bit
game_type_id bigint unsigned

[game_type]
game_type_id bigint unsigned
game_type_desc varchar(13)
在这么大的桌子上要小心alters语句。
在发出alter之前,请始终进行备份。

我会立即停止在SELECT表达式和GROUP BY中使用MID()查询。根据您的查询条件,MySQL在解析时不一定会将其缓存在单个表达式中,因此至少可以尝试以下方法:

SELECT MID(game,{$len},1) AS move,
   COUNT(*) AS games,
   SUM(win) AS wins,
   SUM(loss) AS losses
   FROM games WHERE game LIKE '{$game}%' GROUP BY move;

这不是世界上最大的变化,但应该会有一点不同。除此之外,我认为,在不改变数据存储方式的情况下,优化这一缺陷的唯一真正方法是预先计算这些值,并在游戏结束时增加这些值。

不幸的是,我对
$game
使用了几乎相同频率的所有不同值。这只意味着您将根据将要使用的$games的不同值进行聚合需要。即使范围在数百万,也可能比单个记录小得多。这将需要比当前使用的多出数亿行,每行也需要更多的空间。这个表已经接近10Gb了,所以我认为这是不可行的。但是你的主要问题是计算成本太高。使用更多的磁盘空间来构建“缓存”表可能会有所帮助。好的,我想我会研究构建某种缓存系统。不过,我仍然担心它会占用多少空间。在数字值上使用LIKE是非常错误的。对于MID()的分组也是一样,这听起来是错误的。你为什么这么做?最后,与其为“赢”和“输”设置多个列,为什么不设置一个“结果”列,其值可以是“赢”、“输”或“平局”。它可以是“相似”或“大于”或“小于”。我认为这两种方式都没有多大区别。按MID()分组基本上是对
游戏中的下一个数字进行分组。与MID相同(游戏,1,{$len})。无论哪种方式,赢/输都会占用2位空间,所以这并不重要。在数值上使用LIKE涉及类型转换,因此效率必须更低。至于赢/输列,恐怕它们每个占用1字节,而不仅仅是1位。至于问“为什么”,也许我应该说得更具体一些。真正的问题是,为什么必须使用LIKE按范围进行查询,然后使用数字的文本表示对结果进行分组。我不知道你的“游戏”栏实际上包含什么数据(顺便说一句,这确实是你应该描述的事情),但你的问题似乎是你的数据库设计,而不是它产生的低效查询。哦,那么定义为
bit(1)
的栏仍然占用整个字节?真烦人。
LIKE
只选择那些与
$game
匹配的结果(大于和小于也可以),然后
分组,按下一个数字分组。我也可以使用
逐层分组(游戏/10)
来达到同样的效果。你似乎不明白问题不在于你如何做事,而在于你为什么做事。例如,为什么必须使用LIKE查找结果和MID()对结果进行分组。“游戏”代表什么?如果它代表不止一件事,那么你就有问题了。实际上,
$game
是一个15位的五进制数:P同样,正如问题中所说,MID()必须能够接受5个不同的长度值,这样就形成了一个巨大的额外表!每次运行查询时,它都会在内存中创建一个巨大的额外表,而不会给您索引的好处。哦,非常感谢。我没有意识到我可以通过我刚刚编的一个合谋来分组。另外,我应该注意,我已经将
LIKE
更改为
>x和
语句
SELECT MID(game,{$len},1) AS move,
   COUNT(*) AS games,
   SUM(win) AS wins,
   SUM(loss) AS losses
   FROM games WHERE game LIKE '{$game}%' GROUP BY move;