我找不出爲什麼我的查詢變慢。它歸結爲四個表格:團隊,玩家,設備和元數據。玩家和裝備的記錄有一個FK隊,使球隊成爲球員和裝備的父母。並且這三個表中的每行都有一個元數據記錄,用於存儲創建日期,創建者用戶ID等內容。如何優化包含兩個左連接的MySQL查詢?
我想一次檢索所有玩家和設備記錄,屬於特定團隊,按創建日期排列。我從元數據表開始,通過metadata_id FK離開播放器和設備表,但是當我嘗試過濾SELECT以僅檢索某個團隊的記錄時,查詢會在有很多行時減慢大的時間。
下面是該查詢:
SELECT metadata.creation_date, player.id, equipment.id
FROM
metadata
JOIN datatype ON datatype.id = metadata.datatype_id
LEFT JOIN player ON player.metadata_id = metadata.id
LEFT JOIN equipment ON equipment.metadata_id = metadata.id
WHERE
datatype.name IN ('player', 'equipment')
AND (player.team_id = 1 OR equipment.team_id = 1)
ORDER BY metadata.creation_date;
你需要補充大量的行真正看到慢下來,大約10,000爲每個表。我不明白的是,爲什麼如果我只在一張桌子的where子句中進行篩選,它真的很快,例如:「... AND player.team_id = 1」但是當我添加另一個以使其成爲「.. AND(player.team_id = 1 OR equipment.team_id = 1)「需要很長的時間。
以下是表和數據類型。請注意,有一件事情似乎有很大幫助,但不是那麼多,是metadata_id和team_id的播放器和設備上的組合鍵。
CREATE TABLE `metadata` (
`id` INT(4) unsigned NOT NULL auto_increment,
`creation_date` DATETIME NOT NULL,
`datatype_id` INT(4) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE `datatype` (
`id` INT(4) unsigned NOT NULL auto_increment,
`name` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE `team` (
`id` INT(4) unsigned NOT NULL auto_increment,
`metadata_id` INT(4) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE `player` (
`id` INT(4) unsigned NOT NULL auto_increment,
`metadata_id` INT(4) unsigned NOT NULL,
`team_id` INT(4) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE `equipment` (
`id` INT(4) unsigned NOT NULL auto_increment,
`metadata_id` INT(4) unsigned NOT NULL,
`team_id` INT(4) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
ALTER TABLE `metadata` ADD INDEX ( `datatype_id`),
ADD INDEX (`creation_date`);
ALTER TABLE `team` ADD INDEX ( `metadata_id`);
ALTER TABLE `player` ADD INDEX `metadata_id` ( `metadata_id`, `team_id`),
ADD INDEX (`team_id`);
ALTER TABLE `equipment` ADD INDEX `metadata_id` ( `metadata_id`, `team_id`),
ADD INDEX (`team_id`);
ALTER TABLE `metadata` ADD CONSTRAINT `metadata_ibfk_1` FOREIGN KEY (`datatype_id`) REFERENCES `datatype` (`id`);
ALTER TABLE `team` ADD CONSTRAINT `team_ibfk_1` FOREIGN KEY (`metadata_id`) REFERENCES `metadata` (`id`);
ALTER TABLE `player` ADD CONSTRAINT `player_ibfk_1` FOREIGN KEY (`metadata_id`) REFERENCES `metadata` (`id`);
ALTER TABLE `player` ADD CONSTRAINT `player_ibfk_2` FOREIGN KEY (`team_id`) REFERENCES `team` (`id`);
ALTER TABLE `equipment` ADD CONSTRAINT `equipment_ibfk_1` FOREIGN KEY (`metadata_id`) REFERENCES `metadata` (`id`);
ALTER TABLE `equipment` ADD CONSTRAINT `equipment_ibfk_2` FOREIGN KEY (`team_id`) REFERENCES `team` (`id`);
INSERT INTO `datatype` VALUES(1,'team'),(2,'player'),(3,'equipment');
請注意,我知道我可以很容易做的播放器和設備用於給定小組ID 2個SELECTS的UNION加快這,但我使用本身不支持聯盟的ORM和所以我寧願嘗試查看是否可以優化此查詢。另外,我只是很好奇。
哦,拜託,你可以用真正的baz替換你的baz-bar-foo foo嗎? – markus 2009-08-12 21:52:40
抱歉,我認爲我失去了你,但我是否正確地猜測你的意思是用真正的表名替換foo,bar,baz? – mcsnolte 2009-08-12 21:54:29
的確如此,因爲正如你所看到的那樣,這樣很難遵循......就像使用變量名稱foo和baz的代碼......但是如果你想要獲得你的baz,我就是吧! – markus 2009-08-12 21:57:44