egg*_*yal 21 mysql query-optimization
查看查询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 Using temporary 1 SIMPLE Q ref PRIMARY,S S 2 const 204 Using index 1 SIMPLE V ref PRIMARY,n,Q Q 5 const,db.Q.QID 6 Using where; Using index; Distinct 1 SIMPLE R1 ref PRIMARY,L L 154 const,db.V.VID 447 Using index; Distinct 1 SIMPLE W eq_ref PRIMARY,w PRIMARY 5 const,db.R.RID,const 1 Using where; Distinct 1 SIMPLE R2 eq_ref PRIMARY,L PRIMARY 156 const,db.W.RID,const 1 Using where; Distinct
我是否正确解释执行计划的最后一行如下:
R2
每个输出行只需要获取一行;R2
?如果是这样,我的问题在于在最后一步中发生的过滤.如果条件导致没有过滤(例如WHERE `Col_1_to_3` IN (1,2,3)
),则查询运行得非常快(~50ms); 但是,如果条件限制了selected(WHERE `Col_1_to_3` IN (1,2)
)行,则查询需要相当长的时间(~5s).如果限制是单个匹配(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
;
Run Code Online (Sandbox Code Playgroud)
表的定义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
Run Code Online (Sandbox Code Playgroud)
Mar*_*ams 15
取决于你的目标和查询.
通常,对于EXPLAIN中具有a的每一行Using where
,您需要使用索引(possible keys
和keys
列).这些是您的过滤器,包括WHERE和ON.说得Using index
更好.这意味着有一个覆盖索引,MySQL可以直接从索引中检索数据,而不是访问表数据中的行.
Using where
应该查看没有的行,并返回大量的行.这些是表中所有行的返回值.我不知道你的查询是什么,所以我不知道这里是否要惊慌.尝试过滤结果集以减小大小并提高性能.
你通常应该尽量避免看到Using filesort
或者Using temporary
,尽管如果你不期待它们那些只是坏事.
Filesort通常与ORDER子句一起出现.您通常希望MySQL使用覆盖索引(Using index
),以便从服务器按顺序返回行.如果它们不是,那么MySQL必须使用filesort对它们进行排序.
Using temporary
当它引用派生表时可能会很糟糕,因为它们没有索引.看来你已经明确地创建了一个带索引的临时表,所以在这里,它并不坏.有时,您唯一的选择是使用派生表,因此Using temporary
.
归档时间: |
|
查看次数: |
18323 次 |
最近记录: |