我有一个复杂的选择查询和一个巨大的表。
我正在运行这个select
语句,同时有一个Update
语句到达并尝试更新表。
恕我直言-更新需要排他锁-因此更新语句必须等到选择命令完成。
我对吗 ?
我该怎么做才能:执行复杂的
select
,并让update
命令运行(目前我不关心脏数据)
我有一个复杂的选择查询和一个巨大的表。
我正在运行这个select
语句,同时有一个Update
语句到达并尝试更新表。
恕我直言-更新需要排他锁-因此更新语句必须等到选择命令完成。
我对吗 ?
我该怎么做才能:执行复杂的select
,并让update
命令运行(目前我不关心脏数据)
是的——在一定程度上。
持有SELECT
共享锁的时间取决于事务的隔离级别:
READ UNCOMMITTED
- 根本没有获取共享锁 -UPDATE
没有被阻塞READ COMMITTED
- 仅在读取数据期间获取共享锁 -UPDATE
可能会在很短的时间内被阻塞REPEATABLE READ
并且SERIALIZABLE
- 获取共享锁并保持到事务结束 -UPDATE
阻塞直到SELECT
事务结束从技术上讲,该UPDATE
语句首先在读取要更新的行的当前值期间获得一个UPDATE
锁——它与共享锁(由 使用)兼容。SELECT
完成后,Update
锁将升级为独占锁,以便将新数据写入表中。
当您同时运行这两个语句(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隔离并停止担心这个问题?