9

我有一个复杂的选择查询和一个巨大的表。

我正在运行这个select语句,同时有一个Update语句到达并尝试更新表。

恕我直言-更新需要排他锁-因此更新语句必须等到选择命令完成。

  1. 我对吗 ?

  2. 我该怎么做才能:执行复杂的selectupdate命令运行(目前我不关心脏数据

4

2 回答 2

16

是的——在一定程度上。

持有SELECT共享锁的时间取决于事务的隔离级别:

  • READ UNCOMMITTED- 根本没有获取共享锁 -UPDATE没有被阻塞
  • READ COMMITTED- 仅在读取数据期间获取共享锁 -UPDATE可能会在很短的时间内被阻塞
  • REPEATABLE READ并且SERIALIZABLE- 获取共享锁并保持到事务结束 -UPDATE阻塞直到SELECT事务结束

从技术上讲,该UPDATE语句首先在读取要更新的行的当前值期间获得一个UPDATE锁——它与共享锁(由 使用)兼容。SELECT

完成后,Update锁将升级为独占锁,以便将新数据写入表中。

于 2012-08-06T13:47:02.013 回答
6

当您同时运行这两个语句(SELECT 和 UPDATE)时,实际行为基本上是随机的。这是因为这两个操作都不是瞬时的。为简化起见,将您的表视为一个列表,并且 SELECT 遍历此列表,一次查看一行。UPDATE 也在尝试更新一行或多行。当 UPDATE 尝试更新SELECT后面的行时,没有任何反应(没有阻塞),因为 SELECT 已经超过了 UPDATE 点。如果 UPDATE 正在尝试更新 SELECT现在正在查看的行,则 UPDATE 将不得不等待 SELECT 继续前进,这将非常非常快地发生并且 UPDATE 将解除阻塞并成功,SELECT 正在向前推进。但是,如果 UPDATE在 SELECT之前更新一行,则更新将成功,稍后, SELECT 最终将准确到达该行并将停止,阻塞。现在 SELECT 必须等到执行 UPDATE 的事务提交

这是简化的故事。现实生活要复杂得多。SELECT 可以有多个读取点(并行计划)。SELECT 和 UPDATE 都需要选择访问路径,这意味着使用一个或多个二级索引来定位行。复杂查询可能包含导致对表进行多次查找的运算符(例如连接)。SELECT 和 UPDATE 都可以进行书签查找以获取 BLOB 数据,这显着改变了锁定行为。基数估计可能会导致 SELECT 以高粒度锁模式运行(例如,表级共享锁)。UPDATE 可以触发锁升级,升级可以失败也可以成功。选择不同的访问路径会导致死锁由于散列冲突,可能会发生假锁争用. 只有无数个变量对此有发言权。而且我什至没有提到更高的隔离级别(可重复读取,可序列化)。

也许您应该使用SNAPSHOT隔离并停止担心这个问题?

于 2012-08-06T14:03:57.147 回答