我找不出为什么我的查询变慢。它归结为四个表格:团队,玩家,设备和元数据。玩家和装备的记录有一个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