Mysql 在更新运行期间,SQL update会影响其子查询吗?
我正在编写一个复杂的更新查询,大致如下所示:Mysql 在更新运行期间,SQL update会影响其子查询吗?,mysql,sql,database,oracle,postgresql,Mysql,Sql,Database,Oracle,Postgresql,我正在编写一个复杂的更新查询,大致如下所示: update table join (select y, min(x) as MinX from table group by y) as t1 using (y) set x = x - MinX 这意味着变量x会根据子查询进行更新,子查询也会处理变量x——但是这个x不能通过运行的更新命令进行修改吗?这不是个问题吗?我的意思是,在普通编程中,你通常必须显式地处理这个问题,也就是说,将新值从旧值存储到另一个地方
update table join
(select y, min(x) as MinX
from table
group by y) as t1
using (y)
set x = x - MinX
这意味着变量x
会根据子查询进行更新,子查询也会处理变量x
——但是这个x
不能通过运行的更新命令进行修改吗?这不是个问题吗?我的意思是,在普通编程中,你通常必须显式地处理这个问题,也就是说,将新值从旧值存储到另一个地方,然后在工作完成后,用新值替换旧值。。。但是SQL数据库将如何做到这一点呢?
我对任何观察或实验都不感兴趣。我想从docs或sql标准中得到一个片段,说明在这种情况下定义的行为是什么。我使用的是MySQL,但答案也适用于其他PostgresQL、Oracle等。特别是一般SQL标准的,非常感谢。谢谢 ***已编辑** 从目标表中选择 发件人: FROM子句中的子查询可以返回标量、列、行或表。FROM子句中的子查询不能是相关子查询,除非在联接操作的ON子句中使用 因此,是的,您可以执行上述查询 问题 这里确实有两个问题。存在并发性,或者确保没有其他人从我们脚下更改数据。这是通过锁定来处理的。处理新值与旧值的实际修改是使用派生表处理的 锁定 在上面的查询中,使用InnoDB,MySQL首先执行SELECT,并对表中的每一行分别获取读取(共享)锁。如果在SELECT语句中有WHERE子句,则仅锁定所选记录,WHERE范围也会导致锁定任何间隙 A阻止任何其他查询获取写锁,因此当记录被读锁定时,无法从其他位置更新记录 然后,MySQL分别对表中的每个记录获取写(独占)锁。如果在UPDATE语句中有WHERE子句,那么只有特定的记录才会被写锁定,同样,如果WHERE子句选择了一个范围,那么就会锁定一个范围 任何具有上一次选择的读取锁定的记录都将自动升级为写入锁定 防止其他查询获取读锁或写锁 您可以使用在锁定模式下运行它,启动事务,执行查询(但不提交),然后在Innotop中看到锁定。此外,您还可以在不使用Innotop的情况下,通过
显示引擎INNODB状态
查看详细信息
死锁
如果同时运行两个实例,则查询容易发生死锁。如果查询A获得了读锁,那么查询B获得了读锁,那么查询A必须等待查询B的读锁释放,然后才能获得写锁。然而,查询B在完成之前不会释放读锁,除非它能够获取写锁,否则它不会完成。查询A和查询B处于僵持状态,因此出现了死锁
因此,您可能希望执行显式表锁,以避免大量的记录锁(这会占用内存并影响性能),并避免死锁
另一种方法是使用选择。。。要更新您的内部,请选择。这是从所有行上的写锁开始的,而不是从读取和升级它们开始的
派生表
对于内部SELECT,MySQL创建一个。派生表是驻留在由MySQL自动创建的临时表中的数据的实际非索引副本(与显式创建并可以向其中添加索引的临时表相反)
因为MySQL使用派生表,所以这是您在问题中提到的临时旧值。换句话说,这里没有魔法。MySQL使用一个临时值,就像在其他任何地方一样
您可以通过对UPDATE语句(MySQL 5.6+支持)进行解释来查看派生表。虽然注意到您不能基于表自身的数据对表进行更新,但您应该能够通过
update Table1,
(select T2.y, MIN( T2.x ) as MinX from Table1 T2 group by T2.y ) PreQuery
set Table1.x = Table1.x - PreQuery.MinX
where Table1.y = PreQuery.y
我不知道使用JOIN与逗号列表版本的语法是否有不同的路径,但是通过完整的预查询,您必须首先应用它,以获得一次完成的结果,并通过WHERE连接(通过WHERE)以实际执行更新。Oracle在11.2版本中有此功能 一致的 为每个查询提供结果集,保证数据一致性, 没有用户的操作。隐式查询,如隐式查询 由UPDATE语句中的WHERE子句保证 一组结果。但是,隐式查询中的每个语句并不 查看DML语句本身所做的更改,但将数据视为 它在做出改变之前就存在了
正确的RDBMS使用
语句级读取一致性
,确保语句看到(选择)语句开始时的数据。所以你害怕的情景不会发生
问候,Rob。< /p>什么数据库引擎,你从同一个表中选择你正在更新的?@ MarcusAdams,从同一个表中考虑它是一个最终的SQL查询。使用InnoDB,但是越一般的答案(引擎->mysql->SQL)越好。“mysql不允许您从您试图更新的同一个表中进行选择”-Marcus,这不是真的。这个查询和我发布的完全一样。@Tomas,啊,你说得对。MySQL允许使用JOIN子句从目标表中进行选择。这又回到了一个锁定问题。我已经编辑了上面的答案