Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/wix/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 分组查询优化_Mysql_Group By_Query Optimization_Myisam - Fatal编程技术网

Mysql 分组查询优化

Mysql 分组查询优化,mysql,group-by,query-optimization,myisam,Mysql,Group By,Query Optimization,Myisam,数据库是MySQL和MyISAM引擎 表定义: CREATE TABLE IF NOT EXISTS matches ( id int(11) NOT NULL AUTO_INCREMENT, game int(11) NOT NULL, user int(11) NOT NULL, opponent int(11) NOT NULL, tournament int(11) NOT NULL, score int(11) NOT NULL,

数据库是MySQL和MyISAM引擎

表定义:

CREATE TABLE IF NOT EXISTS  matches  (
   id  int(11) NOT NULL AUTO_INCREMENT,
   game  int(11) NOT NULL,
   user  int(11) NOT NULL,
   opponent  int(11) NOT NULL,
   tournament  int(11) NOT NULL,
   score  int(11) NOT NULL,
   finish  tinyint(4) NOT NULL,
  PRIMARY KEY ( id ),
  KEY  game  ( game ),
  KEY  user  ( user ),
  KEY  i_gfu ( game , finish , user )
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3149047 ;
我已在
(游戏、完成、用户)
上设置了索引,但此
分组依据
查询仍需要0.4-0.6秒才能运行:

SELECT user AS player
     , COUNT( id ) AS times
FROM matches
WHERE finish = 1
  AND game = 19
GROUP BY user
ORDER BY times DESC
解释
输出:

| id | select_type | table   | type | possible_keys | key   | key_len | 
|  1 |  SIMPLE     | matches |  ref | game,i_gfu    | i_gfu |    5    | 

|  ref        |   rows |   Extra                                      |
| const,const | 155855 | Using where; Using temporary; Using filesort |
有什么办法可以让它更快吗?该表有大约800K条记录


编辑:我将
COUNT(id)
更改为
COUNT(*)
,时间下降到0.08-0.12秒。我想我在制作索引之前已经试过了,但之后又忘了更改

在解释输出中,使用索引解释加速:

|   rows |   Extra                                                   |
| 168029 | Using where; Using index; Using temporary; Using filesort |
(旁白:下降5倍是否正常?)


大约有2000个用户,因此最终的排序,即使使用filesort,也不会影响性能。我试过不按下单,但它仍然需要几乎相同的时间。

去掉“游戏”键-它与“I_gfu”是多余的。因为“id”是唯一的count(id),所以只返回每个组中的行数,所以您可以去掉它并用count(*)替换它。这样尝试并粘贴EXPLAIN的输出:

SELECT user AS player, COUNT(*) AS times
FROM matches
WHERE finish = 1
AND game = 19
GROUP BY user
ORDER BY times DESC

嗯,很难。尝试重新排序您的索引:将
用户
列放在第一位(因此将索引设置为
(用户、完成、游戏)
),因为这会增加组成员使用索引的机会。但是,在一般情况下,如果将使用的聚合函数限制为MIN和MAX(请参阅和),则GROUP BY只能使用索引。您的order by也没有真正的帮助。

解释验证了查询中使用的
(游戏、完成、用户)
索引。对我来说,这似乎是最好的索引。这可能是硬件问题吗?您的系统RAM和CPU是什么?

我认为大部分时间都花在提取800k行中的150k行上,更重要的是排序(两次,包括通过读取索引跳过的一次)。我怀疑您是否能够对其进行比现在更多的优化。

正如其他人所指出的,您可能已经达到了优化查询本身的能力极限。接下来,您应该查看服务器中
max\u heap\u table\u size
tmp\u table\u size
变量的设置。默认值为16MB,这对于您的表来说可能太小。

此查询的缺点之一是您按聚合排序。这意味着在生成完整的结果集之前,不能返回任何行;没有索引可以修复这个问题(无论如何,对于mysql myisam)


不过,您可以相当容易地对数据进行反规范化,以克服这一问题;例如,您可以添加一个insert/update触发器,在摘要表中添加一个带有索引的计数值,以便立即开始返回行

是的。排序不,它不花时间排序。这不是你的查询计划所建议的。也不是你的问题。他们都说至少需要一种我的意思是,它花在分类上的时间比花在分组上的时间要短。我也不能怪它这么做。。。它根据您的查询计划将许多行(表的一半?)分组为150k行。:-)事实上,我99%肯定你在浪费时间试图优化它:你当前的三列索引允许直接进入颈静脉,就像在获取相关行并按原样分组一样。然后需要对它们进行分类,这也需要时间。老实说,我认为你们还可以做其他事情。如果有什么不同的话,我真的很惊讶计划者竟然决定使用索引,因为你要检索20%的表。我尝试过该索引,还尝试了
(用户、游戏、完成)
,并强制使用它,但速度更慢。奇怪。我有种感觉,如果将GROUPBY和ORDERBY结合起来,您将无法做得更好:如果查询速度太慢,您可能需要创建一个显式聚合表。使用filesort显示的事实表明,无法从任何索引中执行排序:可能尝试将
id
添加到索引中?你是说
(游戏,完成,用户,id)
索引?好吧,我会说,在大小上尝试一下,但如果使用
COUNT(*)
有帮助,那可能不会有多大好处。内存是1GB。CPU是(我认为)AMD Opteron四核3.5GHz。我猜你的瓶颈是RAM。我建议将其提升到4GB.4GB以处理900k行~30字节的表?;)甚至还不到30兆字节;)@lucek你的数学是正确的,但是现在操作系统开销占用了很多内存。此外,任何其他正在运行的应用程序都将消耗RAM。现在4GB已经是相当标准的了。@也许这里有一个基于软件的建议,可以加快速度。您的表、索引和SQL结构对我来说似乎很好,所以我怀疑任何调整都会有所帮助。@Thomas Jones Low关于服务器变量的建议可能会有所帮助。如果没有什么帮助的话,额外几GB的RAM是相当便宜的。thnx的建议是,两种设置都是64M。count(*)的性能比count(id)快得多的原因是MySQL对count(*)的情况进行了特定的优化。count(id)案例第二次遍历数据以检索结果,其中count(*)使用现有的内部行计数器。尽可能使用count(*)。