2017-04-26 9 views
0

私は3つのテーブルを持っています。最初のものはmap_lifeと呼ばれ、2番目のものはscriptsと呼ばれ、3番目のものはnpc_dataと呼ばれます。複数の結合を実行しているMySQLクエリが実行に時間がかかりすぎる

IDが一致した場合、私はまたnpc_dataからscriptsからscript列とstorage_cost列を取得中map_lifeからすべてのプロパティを取得するには、次のクエリを実行していますよ。

SELECT life.* 
    , script.script 
    , npc.storage_cost 
    FROM map_life life 
    LEFT 
    JOIN scripts script 
    ON script.objectid = life.lifeid 
    AND script.script_type = 'npc' 
    LEFT 
    JOIN npc_data npc 
    ON npc.npcid = life.lifeid 

あなたが見ることができるようにscripts idがobjectidあるとnpc_data idがnpcidありながら、map_life IDは、lifeidです。

このクエリの実行には約5秒かかりますが、私はその理由を知りません。ここに3つのテーブルすべてのCREATE文があります。何か不足しているのでしょうか?このクエリの

CREATE TABLE `mcdb83`.`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`), 
    KEY `lifetype` (`mapid`,`life_type`) 
) ENGINE=InnoDB AUTO_INCREMENT=32122 DEFAULT CHARSET=latin1; 

CREATE TABLE `mcdb83`.`scripts` (
    `script_type` enum('npc','reactor','quest','item','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(30) 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. '; 

CREATE TABLE `mcdb83`.`npc_data` (
    `npcid` int(11) NOT NULL, 
    `storage_cost` int(11) NOT NULL DEFAULT '0', 
    `flags` set('maple_tv','is_guild_rank') NOT NULL DEFAULT '', 
    PRIMARY KEY (`npcid`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 
+0

良い。次に、上記のEXPLAINを指定します。 – Strawberry

答えて

0

は:scripts(object_id, script_type, script)npc_data(npcid, storage_cost)

SELECT l.*, s.script, npc.storage_cost 
FROM map_life l LEFT JOIN 
    scripts s 
    ON s.objectid = l.lifeid AND 
     s.script_type = 'npc' LEFT JOIN 
    npc_data npc 
    ON npc.npcid = l.lifeid; 

あなたは上のインデックスをしたいです。これらの索引の列の順序は重要です。

0
  1. map_life.lifeidインデックスが定義されていないため、結合によって完全なテーブルスキャンが行われます。 map_life.lifeidフィールドにインデックスを定義します。

  2. スクリプトテーブルでは、プライマリキーはscript_typehelperobjectidの順で次のフィールドに定義されています。結合はobjectidで行われ、一定のフィルター基準がscript_typeにあります。インデックス内のフィールドの順序が間違っているため、MySQLはこのクエリにプライマリキーを使用できません。このクエリでは、インデックス内のフィールドの順序はb:objectid,script_type,helperとなります。

上記は、ジョインを大幅に高速化します。この場合、MySQLはテーブルに触れる必要がないため、インデックスが実際にクエリに含まれるすべてのフィールドをカバーする場合、クエリの速度をさらに上げることができます。 object_id, script_type, scriptnpcid, storage_costインデックスをnpc_dataテーブルに:

scriptsテーブルに次のフィールドと順序でインデックスを追加することを検討してください。ただし、これらの索引は挿入/更新/削除文を遅くする可能性があるため、これらの索引を本番環境に追加する前にいくつかのパフォーマンス・テストを実行してください。

関連する問題