mysql - 为什么这个 update-with-join mysql 查询这么慢?

标签 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=?

该表在 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

但为什么原始语句没有按预期执行,我需要如何重新表述才能更好地工作?

应要求,这里是创建表的简化版本:

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

我没有尝试添加复合索引(实际上,我没有现场执行此操作所需的访问级别);但我看不出它有什么帮助,试图思考数据库引擎将如何尝试解决双重不平等。

最佳答案

您可以“强制”(至少到 5.5,5.6 版对优化器进行了多项改进,这可能会使重写变得多余)MySQL 通过将拆分的第一部分作为子查询,然后将其用作派生表并连接到表 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 ; 

效率仍然取决于选择两个索引中的哪一个来限制要更新的行。在使用这两个索引中的任何一个之后,仍然需要进行表查找来检查另一列。所以,我建议你在 (lft, rgt) 上添加一个复合索引,在 (rgt, lft) 上添加一个复合索引,这样只有一个索引用于查找应更新的行.

我假设您正在使用 Nested Set 并且此更新的效率在大表上不会很好,因为查询有 2 个范围条件并且限制了 B 树索引的效率。

关于mysql - 为什么这个 update-with-join mysql 查询这么慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18871200/

相关文章:

mysql - 如何重置mysql中的自动增量字段值

php - 为批量更新提交的一个或多个行缺少指定的索引。 (代码点火器)

php - 在 PHP-MySQL 中基于子字符串检索行

sql - 分组依据中的最大行数

sql - 如何使用 SAS PROC SQL 进行最后一次观察

php - 性能,检查值是否存在数组或查询

javascript - 从所有匹配的表单元素中删除一个类..最干净的方法?

php - 如何使用Mysql blob下载没有html的文件

php - mysql查询选择所有参数但限制每次出现的参数

javascript - 新浏览器是否以不同方式优化循环?