【发布时间】:2010-11-19 03:05:20
【问题描述】:
我无法弄清楚为什么我的查询变慢了。它归结为四个表:团队、球员、设备和元数据。玩家和设备中的记录对团队有 FK,使团队成为玩家和设备的父级。并且所有这三个表的行在元数据中都有一条记录,其中存储了创建日期、创建者用户 ID 等内容。
我想一次性检索所有属于特定球队的球员和装备记录,按创建日期顺序排列。我从元数据表开始,通过 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)" 这需要很多很多时间。
这里是表格和数据类型。请注意,似乎有很大帮助的一件事是,元数据_id 和团队_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 的玩家和设备执行两个 SELECTS 的 UNION 轻松加快此过程,但我使用的 ORM 本身并不支持 UNION所以我更愿意尝试看看我是否可以优化这个查询。我也只是好奇。
【问题讨论】:
-
拜托,你能把你的 baz-bar-foo foo 换成真正的 baz 吗?
-
对不起,我想我失去了你,但我猜对了,你的意思是用真实的表名替换 foo、bar、baz?
-
没错,因为正如你所看到的,很难像这样理解......就像使用变量名 foo 和 baz 的代码......但如果你想 foo 你的 baz,我吧!
-
好的,现在玩家和装备都属于一个团队了。
标签: optimization mysql left-join polymorphic-associations