Sql - 查询需要很长时间

时间:2014-05-20 15:56:30

标签: mysql sql

我有两张桌子。一个称为map_life,第二个称为scriptsmap_life表有很多行,由名为lifeid的列标识。表scripts中的行由列objectid标识。我想创建一个查询来获取表map_life中的所有行,如果script匹配scripts,还会从lifeid表中添加列objectid,并且objecttypenpc

我创建了以下查询。

SELECT id
    ,lifeid
    ,x_pos
    ,y_pos
    ,foothold
    ,min_click_pos
    ,max_click_pos
    ,respawn_time
    ,flags
    ,script.script
FROM map_life life
LEFT JOIN scripts script 
    ON script.objectid = life.lifeid 
        AND script.script_type = 'npc'

但是,该查询需要很多时间。我能以任何方式调整它吗?感谢。

编辑:我已经运行了EXPLAIN命令,有结果。

    "id","select_type","table","type","possible_keys","key","key_len","ref","rows","Extra"
1,"SIMPLE","life","ALL","","","","",47600,""
1,"SIMPLE","script","ref","PRIMARY","PRIMARY","1","const",1834,"Using where"

编辑2:以下是每个表的创建规范。

map_life

DROP TABLE IF EXISTS `mcdb`.`map_life`;
CREATE TABLE  `mcdb`.`map_life` (
  `id` bigint(21) unsigned NOT NULL AUTO_INCREMENT,
  `mapid` int(11) NOT NULL,
  `life_type` enum('npc','mob','reactor') NOT NULL,
  `lifeid` int(11) NOT NULL,
  `life_name` varchar(50) DEFAULT NULL COMMENT 'For reactors, specifies a handle so scripts may interact with them; for NPC/mob, this field is useless',
  `x_pos` smallint(6) NOT NULL DEFAULT '0',
  `y_pos` smallint(6) NOT NULL DEFAULT '0',
  `foothold` smallint(6) NOT NULL DEFAULT '0',
  `min_click_pos` smallint(6) NOT NULL DEFAULT '0',
  `max_click_pos` smallint(6) NOT NULL DEFAULT '0',
  `respawn_time` int(11) NOT NULL DEFAULT '0',
  `flags` set('faces_left') NOT NULL DEFAULT '',
  PRIMARY KEY (`id`,`lifeid`) USING BTREE,
  KEY `lifetype` (`mapid`,`life_type`)
) ENGINE=InnoDB AUTO_INCREMENT=47557 DEFAULT CHARSET=latin1;

scripts

DROP TABLE IF EXISTS `mcdb`.`scripts`;
CREATE TABLE  `mcdb`.`scripts` (
  `script_type` enum('npc','reactor','quest','item','map','map_enter','map_first_enter') NOT NULL,
  `helper` tinyint(3) NOT NULL DEFAULT '-1' COMMENT 'Represents the quest state for quests, and the index of the script for NPCs (NPCs may have multiple scripts).',
  `objectid` int(11) NOT NULL DEFAULT '0',
  `script` varchar(40) NOT NULL DEFAULT '',
  PRIMARY KEY (`script_type`,`helper`,`objectid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Lists all the scripts that belong to NPCs/reactors/etc. ';

2 个答案:

答案 0 :(得分:1)

您应该根据类型向“script_type”字段添加索引。如果它没有使用可以编制索引的类型,则应尽可能更改类型并编制索引

这是一个链接,讨论有关MySQL的索引的更多信息,http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

答案 1 :(得分:1)

scripts上的主键是:

PRIMARY KEY (`script_type`,`helper`,`objectid`)

多列密钥的顺序非常重要。

来自docs

  

任何不跨越WHERE子句中所有AND级别的索引都不是   用于优化查询。换句话说,能够使用   index,必须在每个AND组中使用索引的前缀。

您在脚本上的主键确实包含script_typeobjectid列,这两列都在加入ON子句中使用:

ON script.objectid = life.lifeid 
    AND script.script_type = 'npc'

但主键还包括这两者之间的helper列,因此MySQL只能使用主键索引进行搜索,使用第一列(script_type)。

因此,对于每次加入,MySQL都必须搜索scripts是' npc'的所有script_type条记录。找到要加入的特定objectid记录。

如果您的ON子句包含如下所有三列,MySQL可以充分利用主键索引:

ON script.objectid = life.lifeid
    AND script.helper = 1
    AND script.script_type = 'npc'

如果您经常查询scripts表而未指定helper列,请考虑更改主键中列的顺序,以便将helper列放在最后:

PRIMARY KEY (`script_type`,`objectid`,`helper`)

然后,您的原始ON子句适用于索引,因为索引前缀包含谓词中的所有列(script_typeobjectid):

ON script.objectid = life.lifeid 
    AND script.script_type = 'npc'

或者,添加一个仅包含ON子句中提到的两列的附加索引:

KEY `scrypt_type_objectid` (`script_type`,`objectid`)