MySQL - 无结果查询非常慢(null)

时间:2012-06-14 00:14:07

标签: mysql performance

我的SQL查询有问题,除非没有结果,否则运行完美无缺。

我有4张桌子:世界(2件),玩家(约2000件),world_chunk(约16000件)和world_block(约100万件)

 SELECT bid,playername FROM worlds 
 JOIN world_chunks ON worlds.id = world_chunks.mainid 
 JOIN world_blocks ON world_chunks.cid = world_blocks.cid 
 JOIN players ON world_blocks.player = players.pid 
 WHERE worldname='world' AND x='-684' AND y='63' AND z='-2234' AND cx ='-43' AND cz='-140'

x,y,z保存在world_blocks中,cx,cz保存在world_chunks和worldname in worlds 所有索引都已设置,除了空结果外,所有索引都非常快。

无论如何我可以加快空洞的结果吗?

非常感谢你们的帮助。

编辑: 这是db结构: http://pastebin.com/rxQQ5mzp

其MySQL InnoDB

EXPLAIN on Emtpy Query:
1   SIMPLE  worlds  ALL PRIMARY,idx_mainid  NULL    NULL    NULL    2      Using where
1   SIMPLE  world_blocks    ALL NULL    NULL    NULL    NULL    766845  Using where; Using join buffer
1   SIMPLE  world_chunks    eq_ref  PRIMARY,idx_cid PRIMARY 4   WatchBlock.world_blocks.cid 1   Using where
1   SIMPLE  players eq_ref  PRIMARY,idx_pid PRIMARY 4   WatchBlock.world_blocks.player  1   

EXPLAIN on Found Query:
1   SIMPLE  worlds  ALL PRIMARY,idx_mainid  NULL    NULL    NULL    2   Using where
1   SIMPLE  world_blocks    ALL NULL    NULL    NULL    NULL    766845  Using where; Using join buffer
1   SIMPLE  world_chunks    eq_ref  PRIMARY,idx_cid PRIMARY 4   WatchBlock.world_blocks.cid 1   Using where
1   SIMPLE  players eq_ref  PRIMARY,idx_pid PRIMARY 4   WatchBlock.world_blocks.player  1 

结果可以为空,因为x,y,z和cx,cz不匹配(所以如果其中一个不在db中,则播放器的结果应为空)

1 个答案:

答案 0 :(得分:0)

Philwinkle是对的,在不发布适当的EXPLAIN的情况下发布SQL查询性能问题并不是特别合适。您还应该为四个表和相关索引发布DDL。您说“所有索引都已设置”,但是在您的关注评论中,您建议您使用的唯一索引是主键,这不足以使查询困扰您。

对于性能问题,记录您正在使用的数据库以及您正在使用的表类型也很有用:您的标记表明这是mysql,这意味着myisam vs innodb是您无法提供的关键信息。最后,你声称“空”结果很慢,但是你没有解释为什么空结果为空,是否为空,因为其中一个连接为空,或者因为其中一个坐标不匹配(如果是, world_block,或world_chunk坐标)。

如果您提供了EXPLAIN数据和基本DDL,我不会写这个,因为现在很可能已经回答了这个问题;在你这样做之前,这个问题无法得到合理的回答。

我能提供的最好的是,您可能需要添加至少一个覆盖部分或全部(x,y,z)和(cx,cy)坐标的索引;但这只是一个有根据的猜测。

编辑:

感谢EXPLAIN,这有帮助。毫无疑问,您已经注意到,world_blocks的全表扫描是最可能的罪魁祸首。鉴于数据库的小尺寸,您为(cid,x,y,z)添加的索引可能是最有帮助的。然而,还有其他几点:

如果这是一个摄取+读取数据库,那么MyISAM是一个合理的选择,但如果您打算执行在线UPDATE或DELETE操作,那么最好不要使用InnoDB。 InnoDB的真正好处是并发/可扩展性的改进而不是参照完整性(尽管你不应低估它的重要性)。

如果此查询中的x,y和z始终为常量,则应考虑将它们移动到索引的前面。事实上,如果你使用InnoDB,这个EXPLAIN建议索引应该只是(x,y,z),因为包括cid只会浪费缓冲区缓存。如果你坚持使用MyISAM,你肯定应该考虑在连接引用的那些字段上使用覆盖索引:(x,y,z,cid,players),因为这会阻止在最终投影之前进行全行读取。

这提出了我的最后一点:当你发现自己遇到无法解释的表现怪癖时,一定要运行EXPLAIN;在你无法解释的性能怪癖消失后总是运行EXPLAIN,并确保它有意义; MyISAM和InnoDB的索引行为几乎总是不同的,并且对一个的优化并不总是对另一个的优化。