Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 在更新运行期间,SQL update会影响其子查询吗?_Mysql_Sql_Database_Oracle_Postgresql - Fatal编程技术网

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子句从目标表中进行选择。这又回到了一个锁定问题。我已经编辑了上面的答案