我有一个复杂的选择查询和一个巨大的表。
我正在运行此select
语句,同时Update
语句到达并尝试更新表。
恕我直言 - 更新需要独占锁 - 因此更新语句必须等待,直到select命令完成。
我是对的吗?
我该怎么做才能:执行复杂select
,和也让update
命令运行(目前我没有关心脏数据)
答案 0 :(得分:15)
是 - 在某种程度上。
SELECT
持有共享锁的时间取决于事务的隔离级别:
READ UNCOMMITTED
- 根本没有获取共享锁定 - UPDATE
未被阻止READ COMMITTED
- 仅在读取数据期间获取共享锁定 - UPDATE
可能会在很短的时间内被阻止REPEATABLE READ
和SERIALIZABLE
- 获取并保留共享锁,直到交易结束 - UPDATE
被阻止,直到SELECT
交易结束从技术上讲,UPDATE
语句首先得到一个UPDATE
锁 - 它与共享锁(由SELECT
使用)兼容 - 在读取时持续一段时间要更新的行的当前值。
完成后,Update
锁将升级为独占锁,以便将新数据写入表中。
答案 1 :(得分:5)
当您同时运行两个语句(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可以触发锁升级,升级可能会失败或成功。 Choosing different access paths can lead to deadlock。 False lock contention can occur due to hash collisions。只有一个无数变量在这里有发言权。我甚至没有提到更高的隔离级别(可重复读取,可序列化)。
也许您应该使用SNAPSHOT隔离并停止担心此问题?