2017-04-26 135 views
0

我有3個表。第一個稱爲map_life,第二個稱爲scripts,第三個稱爲npc_data執行多個連接的MySQL查詢花費太長時間執行

我運行下面的查詢從map_life得到的所有特性,同時也從npc_data如果ID匹配正從scriptsscript列和storage_cost列。

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 

正如你所看到的,map_life id爲lifeid,而scripts id爲objectidnpc_data ID是npcid

此查詢需要約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

對於此查詢:

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; 

你想在指標:scripts(object_id, script_type, script)npc_data(npcid, storage_cost)。這些索引中列的順序很重要。

0
  1. map_life.lifeid沒有任何指標定義,因此加入將導致全表掃描。定義map_life.lifeid字段的索引。

  2. 在腳本表中,主鍵按以下順序定義:script_type,helper,objectid。連接在objectid上完成,並在script_type上存在恆定過濾條件。由於索引中的字段順序錯誤,因此MySQL無法使用主鍵進行此查詢。對於此查詢,索引中字段的順序應爲b:objectidscript_type,helper

以上將顯着加快連接。如果您的索引實際上覆蓋了查詢中的所有字段,那麼您可以進一步提高查詢的速度,因爲在這種情況下,MySQL甚至不需要觸摸這些表。

考慮將以下字段添加到索引中,然後再訂購scripts表:object_id, script_type, scriptnpcid, storage_cost索引到npc_data表。但是,這些索引可能會降低插入/更新/刪除語句的速度,因此在將這些索引添加到生產環境之前,請先進行一些性能測試