MySQL Query有时可以,其他时间需要5分钟!

时间:2010-10-05 13:48:38

标签: sql mysql indexing

我有一张桌子用于高分iPhone游戏。 截至目前,查询已被禁用,因此游戏玩家无法看到分数: - (

表格包含以下字段:

Type    Collation   Attributes  Null    Default Extra   Action
id  int(11)         No      auto_increment                          
date    date            No                                  
timestamp   timestamp           No  CURRENT_TIMESTAMP                               
game_id tinyint(4)          No                                  
game_size   tinyint(4)          No                                  
game_level  tinyint(4)          No                                  
score   float           No                                  
score_string    char(11)    utf8_general_ci     No                                   
name    varchar(50) utf8_general_ci     No                                   
place   varchar(50) utf8_general_ci     No      
device  varchar(128)    utf8_general_ci     Yes NULL                

我为game_id和game_size添加了一个双字段索引 这可能是问题,但我无法弄清楚为什么搜索需要5分钟......

这是占用所有时间的查询。 其他更简单的查询也需要很长时间。

SELECT SQL_CALC_FOUND_ROWS name, MIN(score_string) AS Expr1, place FROM
scores WHERE  game_id="1" AND game_size = "5" AND game_level = "1"
AND date>  "2005-04-14" GROUP BY name, place ORDER BY
MIN(score_string) Limit 0, 100;

当我在phpMyAdmin中测试时,它返回1秒,然后返回几秒0.0015秒,然后再返回1秒。

任何帮助都会受到欢迎。 谢谢! Hanaan

以下是针对建议查询的EXPLAIN:

EXPLAIN SELECT name, score_string, place
FROM scores s
WHERE game_id =1
AND game_size =15
AND game_level =1
AND id = (

SELECT id
FROM scores si
WHERE si.game_id =1
AND si.game_size =15
AND si.game_level =1
AND si.name = s.name
AND si.place = s.place
AND si.date >  '2005-04-14'
ORDER BY si.game_id, si.game_size, si.game_level, si.name, si.place, si.score_string, si.id
LIMIT 1
)
ORDER BY game_id, game_size, game_level, score_string, id

LIMIT 100

d   select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY s   ref game_id,indx1,game_id_2 game_id_2   3   const,const,const   14034   Using where
2   DEPENDENT SUBQUERY  si  ref game_id,indx1,game_id_2 game_id 307 const,const,const,tmi_hcg.s.name,tmi_hcg.s.place    13  Using where

SHOW CREATE TABLE得分

CREATE TABLE `scores` (
 `id` int(11) NOT NULL auto_increment,
 `date` date NOT NULL,
 `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,
 `game_id` tinyint(4) NOT NULL,
 `game_size` tinyint(4) NOT NULL,
 `game_level` tinyint(4) NOT NULL,
 `score` float NOT NULL,
 `score_string` char(11) NOT NULL,
 `name` varchar(50) NOT NULL,
 `place` varchar(50) NOT NULL,
 `device` varchar(128) default NULL,
 PRIMARY KEY  (`id`),
 KEY `game_id` (`game_id`,`game_size`,`game_level`,`name`,`place`,`score_string`,`id`),
 KEY `indx1` (`game_id`,`game_size`,`game_level`,`date`,`id`),
 KEY `game_id_2` (`game_id`,`game_size`,`game_level`,`score_string`,`id`)
) ENGINE=MyISAM AUTO_INCREMENT=81564 DEFAULT CHARSET=utf8

似乎数据越接近今天,响应时间越长:

SELECT name, score_string, place
FROM scores s
WHERE game_id =1
AND game_size =15
AND game_level =1
AND id = ( 
SELECT id
FROM scores si
WHERE si.game_id =1
AND si.game_size =15
AND si.game_level =1
AND si.name = s.name
AND si.place = s.place
AND si.date >  "2010-10-01"
ORDER BY si.game_id, si.game_size, si.game_level, si.name, si.place, si.score_string, si.id
LIMIT 1 ) 
ORDER BY game_id, game_size, game_level, score_string, id
LIMIT 100

这花费了惊人的49秒!

3 个答案:

答案 0 :(得分:4)

确保您拥有以下索引:

scores (game_id, game_size, game_level, date, id)
scores (game_id, game_size, game_level, name, place, score_string, id)

(取决于数据分布,它们中的任何一个都可以有效)。

此外,添加以下索引可能很有用:

scores (game_id, game_size, game_level, score_string, id)

并将查询重写为:

SELECT  name, score_string, place
FROM    scores s
WHERE   game_id = 1
        AND game_size = 5
        AND game_level = 1
        AND id =
        (
        SELECT  id
        FROM    scores si
        WHERE   si.game_id = 1
                AND si.game_size = 5
                AND si.game_level = 1
                AND si.name = s.name
                AND si.place = s.place
                AND si.date > '2005-04-14'
        ORDER BY
                si.game_id, si.game_size, si.game_level, si.name, si.place, si.score_string, si.id
        LIMIT 1
        )
ORDER BY
        game_id, game_size, game_level, score_string, id
LIMIT 100

这些查询与第一个查询相同,但如果您的条件不具有选择性,则更有用。

这两篇文章解释了查询的工作原理:

答案 1 :(得分:2)

最小:where子句中的所有字段都应该有一个索引(未合并)。

最大:最小+名称,地点,score_string。

如果没有关于行数,索引字段值的分布等的更多信息,很难说清楚。

请记住:尝试将最具选择性的字段或首先使用均匀分布的字段编入索引。

确定你的录取率!

答案 2 :(得分:0)

这对SQL查询来说有很多工作要做。找到一列中的最小值,匹配其他列并获得另一列中的范围,更不用说排序了。

如果您没有任何索引,一旦您在表中获得大量记录,这将花费大量时间。当然,放入太多的索引会使插入需要很长时间,所以你不想过度使用它。

如果你运行一个查询,并立即重新运行它,mysql可能会缓存信息,使第二个(和所有后续查询)闪电般快速。我认为这就是为什么你看到长时间的查询,然后他们加快。您需要使用很长时间来访问新索引将有多大帮助。如果你需要告诉mysql摆脱它的缓存,你可以使用“刷新表”(但为你的查询做好准备需要很长时间)。

希望有所帮助。