【发布时间】:2012-04-26 06:59:08
【问题描述】:
查看查询的EXPLAIN 计划,如何确定可以在哪里进行最佳优化?
我很欣赏首先要检查的事情之一是是否使用了良好的索引,但除此之外我有点难过。通过过去的反复试验,我有时发现执行连接的顺序可能是一个很好的改进来源,但是如何通过查看执行计划来确定呢?
虽然我非常希望对如何优化查询有一个很好的总体了解(建议阅读非常感谢!),但我也意识到讨论具体案例通常比抽象讨论更容易。由于我目前正在用这个撞墙,因此非常感谢您的想法:
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE S const PRIMARY,l,p,f4 PRIMARY 2 const 1 使用临时 1 SIMPLE Q ref PRIMARY,S S 2 const 204 使用索引 1 SIMPLE V ref PRIMARY,n,Q Q 5 const,db.Q.QID 6 使用 where;使用索引;清楚的 1 SIMPLE R1 ref PRIMARY,L L 154 const,db.V.VID 447 使用索引;清楚的 1 SIMPLE W eq_ref PRIMARY,w PRIMARY 5 const,db.R.R.RID,const 1 使用 where;清楚的 1 SIMPLE R2 eq_ref PRIMARY,L PRIMARY 156 const,db.W.RID,const 1 使用 where;清楚的我对执行计划最后一行的解释是否正确:
- 因为它的主键完全匹配,所以每个输出行只需要获取一行
R2; - 但是,这些输出行随后会根据适用于
R2?的某些标准进行过滤?
如果是这样,我的问题在于最后一步中发生的过滤。如果条件导致不过滤(例如WHERE `Col_1_to_3` IN (1,2,3)),则查询运行速度非常快(~50ms);但是,如果条件限制了选定的行 (WHERE `Col_1_to_3` IN (1,2)),则查询需要相当长的时间(约 5 秒)。如果限制是单个匹配 (WHERE `Col_1_to_3` IN (1)),优化器会建议一个完全不同的执行计划(其性能略好于 5 秒,但仍比 50 毫秒差很多)。似乎没有更好的索引可以在该表上使用(假设它已经完全使用主键来为每个结果返回一行?)。
应该如何解释所有这些信息?我猜对了吗,因为这样的输出过滤发生在要连接的最终表上,与更早加入表并更快地过滤这些行相比,浪费了大量的精力?如果是这样,如何确定应该在执行计划中何时加入R2?
虽然我拒绝在此处完整包含查询和架构(因为我真的很可能知道要寻找什么,而不仅仅是被告知答案),但我理解有必要推进讨论:
SELECT DISTINCT
`Q`.`QID`
FROM
`S`
NATURAL JOIN `Q`
NATURAL JOIN `V`
NATURAL JOIN `R` AS `R1`
NATURAL JOIN `W`
JOIN `R` AS `R2` ON (
`R2`.`SID` = `S`.`SID`
AND `R2`.`RID` = `R1`.`RID`
AND `R2`.`VID` = `S`.`V_id`
AND `R2`.`Col_1_to_3` IN (1,2) -- this is where performance suffers!
)
WHERE
AND `S`.`SID` = @x
AND `W`.`WID` = @y
;
表R的定义是:
CREATE TABLE `R` (
`SID` smallint(6) unsigned NOT NULL,
`RID` smallint(6) unsigned NOT NULL,
`VID` varchar(50) NOT NULL DEFAULT '',
`Col_1_to_3` smallint(1) DEFAULT NULL,
`T` varchar(255) DEFAULT NULL,
PRIMARY KEY (`SID`,`RID`,`VID`),
KEY `L` (`SID`,`VID`,`Col_1_to_3`),
CONSTRAINT `R_f1` FOREIGN KEY (`SID`) REFERENCES `S` (`SID`),
CONSTRAINT `R_f2` FOREIGN KEY (`SID`, `VID`) REFERENCES `V` (`SID`, `VID`),
CONSTRAINT `R_f3` FOREIGN KEY (`SID`, `VID`, `Col_1_to_3`) REFERENCES `L` (`SID`, `VID`, `LID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
【问题讨论】:
-
你介意也显示查询吗?
-
@MarcusAdams:我不介意,但你会寻找什么?我觉得如果我知道你会看什么,我可能会学到更多……
-
您指的是 col_1_to_3,但我在 EXPLAIN 结果中没有看到这样的列。如果您可以将问题表述为仅与解释有关,换句话说,删除讨论查询的段落,那么我们不需要查询,答案是肯定的。一般来说,我们需要查询、模式和解释,否则我们只是在猜测。
-
嗯..
R2.col_1_to_3确实不在 EXPLAIN 结果中;你希望它出现在哪里?如果可能的话,我真的很想知道您在查询和架构中要寻找的什么...否则下次我在这里时不会再获悉位置! -
@MarcusAdams:根据要求在上面包含查询和架构。