pla*_*rob 4 mysql sql performance join
我有一个应用程序需要更新层次结构中的节点,从ID已知的特定节点向上.我使用以下MySQL语句来执行此操作:
update node as A
join node as B
on A.lft<=B.lft and A.rgt>=B.rgt
set A.count=A.count+1 where B.id=?
Run Code Online (Sandbox Code Playgroud)
该表在id上有一个主键,在lft和rgt上有索引.该声明有效,但我发现它存在性能问题.查看相应select语句的EXPLAIN结果,我看到"B"表检查的行数非常大(可能是整个表).
我可以轻松地将查询拆分为两个独立的查询:
select lft, rgt from node where id=?
LFT=result.lft
RGT=result.rgt
update node set count=count+1 where lft<=LFT and rgt>=RGT
Run Code Online (Sandbox Code Playgroud)
但为什么原始声明没有达到预期的效果,我怎么需要重新制定它才能更好地发挥作用?
根据要求,这是create table的缩写版本:
CREATE TABLE `node` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) NOT NULL,
`lft` decimal(64,0) NOT NULL,
`rgt` decimal(64,0) NOT NULL,
`count` int(11) NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `name` (`name`),
KEY `location` (`location`(255)),
KEY `lft` (`lft`),
KEY `rgt` (`rgt`),
) ENGINE=InnoDB
Run Code Online (Sandbox Code Playgroud)
我没有尝试添加复合索引(实际上,我没有现场执行此操作所需的访问级别); 但我不知道它会如何帮助,试图思考数据库引擎如何尝试解决双重不等式.
您可以"强制"(至少高达5.5,版本5.6对优化器进行了一些改进,这可能会使这种重写变得多余)MySQL首先通过将拆分的第一部分作为子查询来评估表B上的条件然后使用它作为派生表并加入表A:
UPDATE node AS a
JOIN
( SELECT lft, rgt
FROM node
WHERE id = ?
) AS b
ON a.lft <= b.lft
AND a.rgt >= b.rgt
SET
a.count = a.count + 1 ;
Run Code Online (Sandbox Code Playgroud)
效率仍将取决于选择哪两个索引来限制要更新的行.仍然在使用这两个索引中的任何一个之后,需要进行表查找以检查另一列.所以,我建议你添加一个复合索引(lft, rgt)和一个on,(rgt, lft)所以只有一个索引用于查找哪些行应该更新.
我想您正在使用嵌套集,并且此更新的效率在大表上不会很好,因为查询具有2个范围条件并且限制了B树索引的效率.