-1

我的 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 中,worlds 中的 worldname 所有索引都已设置,除了空结果之外的所有内容都非常快。

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

非常感谢你们的帮助。

编辑:这是数据库结构: 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 中,则 player 的结果应该为空)

4

1 回答 1

0

Philwinkle 是对的,在没有发布适当的解释的情况下发布 SQL 查询性能问题并不是特别合适。您还应该发布四个表和相关索引的 DDL。您说“所有索引都已设置”,但是在您的后续评论中,您建议您拥有的唯一索引位于主键上,这对于困扰您的查询来说是不够的。

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

如果您提供了 EXPLAIN 数据和基本 DDL,我就不会写这个,因为这个问题很可能现在已经回答了;就目前而言,除非您这样做,否则无法合理地回答这个问题。

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

编辑:

谢谢你的解释,这有帮助。毫无疑问,您已经注意到,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 的索引行为几乎总是不同的,对一个的优化并不总是对另一个进行优化。

于 2012-06-14T04:43:11.230 回答