我的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中,则播放器的结果应为空)
答案 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的索引行为几乎总是不同的,并且对一个的优化并不总是对另一个的优化。