假设我的更新查询如下所示:
UPDATE a SET
a.colSomething= 1
FROM tableA a WITH (NOLOCK)
INNER JOIN tableB b WITH (NOLOCK)
ON a.colA= b.colB
INNER JOIN tableC c WITH (NOLOCK)
ON c.colC= a.colA
Run Code Online (Sandbox Code Playgroud)
假设以上连接到tableB和tableC需要几分钟才能完成.在表/行锁定方面,整个表在连接期间是否被锁定?或者sql编译器是否足够智能以避免锁定整个表?
与上面的查询相比,通过在实际更新之前首先将连接结果存储在临时表中来获取死锁的可能性较小,如下所示?
SELECT a, b, c
INTO
FROM tableA
INNER JOIN tableB b WITH (NOLOCK)
ON a.colA= b.colB
INNER JOIN tableC c WITH (NOLOCK)
ON c.colC= a.colA
UPDATE a SET a.colSomething=1
FROM tableA a INNER JOIN #tmp t ON a.colA= t.colA
Run Code Online (Sandbox Code Playgroud)
谢谢!
阻塞与死锁
我想你可能会因为DEADLOCKS而导致锁定和阻塞.
在任何更新查询中,SQL Server将锁定所涉及的数据.当此锁定处于活动状态时,其他进程将被阻止(延迟)编辑数据.如果原始更新需要很长时间(从用户的角度来看,比如几秒钟),那么前端系统可能会"挂起"甚至超时用户前端进程并报告错误.
这不是僵局.这种阻塞将自行解决,基本上非破坏性地通过稍微延迟用户或在某些情况下通过强制前端对超时是聪明的.由于长时间运行更新,问题是阻塞,您可以通过增加前端超时来修复必须重新提交的用户.
然而,无论您增加多少超时,都无法解决死锁问题.一个或多个流程将以偏见终止(失去更新).
死锁具有与阻塞不同的根本原因.死锁通常是由前端不一致的顺序逻辑引起的,它在前端的两个不同部分以不同的顺序访问和锁定来自两个表的数据.当这两个部分在多用户环境中同时运行时,它们可能基本上,非确定性地导致死锁,并且基本上无法解决数据丢失(直到解决死锁的原因),而不是通常可以处理的阻塞.
管理阻止
SQL服务器会选择行锁还是整个表锁?
通常,它每次都取决于并且可能不同.根据查询优化器确定将影响的行数,锁可以是行或表.如果它超过一定的阈值,它会去表,因为它会更快.
如何在遵守事务完整性的基本原则的同时减少阻塞?
SQL服务器将尝试锁定要加入的表,因为它们的内容对于生成更新的结果集很重要.您应该能够显示更新的估计执行计划,以查看将根据当前表的大小锁定的内容.如果预测的锁是表,则可以使用行锁提示覆盖,但这并不能保证不会阻塞.它可以减少无意中阻止表中可能不相关的数据的机会.您基本上总是会直接阻止数据更新.
但请记住;
还要记住,在连接表上采取的锁定将是共享锁.这意味着其他进程仍然可以从这些表中读取,它们无法更新它们,直到您使用它们作为参考完成更新.相反,其他进程将主动阻止尝试简单地读取您更新的数据具有独占锁定(正在更新的主表).
所以,连接表仍然可以读取.要更新的数据将被独占锁定为一组记录,直到更新完成或失败并作为一个组回滚.
| 归档时间: |
|
| 查看次数: |
15243 次 |
| 最近记录: |