Sql 确定锁升级的阈值
我有一个大约有250万条记录的表,将更新大约70万条记录,并希望在允许其他用户查看数据的同时更新这些记录。我的update语句如下所示:Sql 确定锁升级的阈值,sql,sql-server,sql-server-2005,Sql,Sql Server,Sql Server 2005,我有一个大约有250万条记录的表,将更新大约70万条记录,并希望在允许其他用户查看数据的同时更新这些记录。我的update语句如下所示: UPDATE A WITH (UPDLOCK,ROWLOCK) SET A.field = B.field FROM Table_1 A INNER JOIN Table2 B ON A.id = B.id WHERE A.field IS NULL AND B.field IS NOT NULL 我想知道是否有办法确定sql server将在什么时候升级对
UPDATE A WITH (UPDLOCK,ROWLOCK)
SET A.field = B.field
FROM Table_1 A
INNER JOIN Table2 B ON A.id = B.id WHERE A.field IS NULL
AND B.field IS NOT NULL
我想知道是否有办法确定sql server将在什么时候升级对update语句的锁定(因为我不希望锁定整个表)
我没有权限运行服务器跟踪以查看锁是如何应用的,因此是否有其他方法可以知道锁将在何时升级以覆盖整个表
谢谢 一旦语句在对象的单个实例上获取了5000个行或页级锁,就会尝试升级这些锁。如果此尝试失败,因为另一个事务具有冲突的锁,那么它将在每获得一个额外的1250个锁后重试
我不确定你是否真的可以把这些数字当作福音,或者是否还有比这更微妙的地方(我猜你总是可以在任何数量的锁上达到实例的内存限制)
ROWLOCK
提示并不能阻止锁升级,它只是通知服务器它不应该采用初始锁定级别并从行开始
然后,行锁可以升级为表锁
要使表数据在更新期间可供读取,请使用
SNAPSHOT
事务隔离级别。正如@Martin所述,5000是BOL给出的数字,但我发现实际数字在生产中有所不同
您有两个选择:
1) 批量更新,并尝试将batchsize保持在5000以下
2) 通过以下方式禁用锁升级(小心):
- *ALTER表(sql2k8)
- *跟踪标志1211/1224 ()
- 通过其他锁定技巧
DECLARE@BatchSize int;
设置@BatchSize=;
开始训练
使用(UPDLOCK、ROWLOCK)更新TOP(@BatchSize)A
设置A.field=B.field
来自表1 A
A.id=B.id上的内部联接表2 B
其中A.field为空
并且B.field不为空
挑选
*
从…起
sys.dm_传输锁
哪里
[请求会话id]=@@spid
回降
这是否意味着,如果您保持一个以独占方式锁定一行的打开事务(您知道大规模更新不会尝试访问),SQL Server将只使用页面锁定(从而避免OP所关心的表锁定)。@Damien-是的。如果另一个事务在表上已经有IX
锁,它将永远无法获取独占表锁。我想在某个时候,它可能会放弃整个过程,但如果它用于锁的内存太多。只锁定一行以强制执行页/行锁而不是表锁会是一个好主意吗?我想,就像所有区域一样,只有在确定了默认行为后,才从SQL server中取消管理不适合您的工作负载,并且已经研究了备选方案(例如快照隔离)和缺点。@Damien:SQL Server
将尝试升级锁,这将阻止更新
事务,因为此升级将与单行锁定事务持有的行锁冲突。在等待时,它仍将保留当前获取的排他行级锁。在使用快照隔离级别时,我是否还需要行锁提示,或者(假设我正在更新的行数超过5k),这不会产生任何效果?@Davin:Snapshot
隔离查询根本不请求读取锁。请注意,您应该将读取事务快照隔离,而不是写入事务。@Quassnoi-我的主要问题是前端应用程序读取数据(其中隔离级别/锁无法更改)因此,我需要的是在数据被更新时只逐行锁定数据,这样用户仍然可以查看数据(而不锁定整个表)——这可能吗?他们目前处于什么隔离级别?如果read committed
更改为read committed snapshot
将需要零代码更改(尽管它确实对tempdb
有影响,您应该首先进行研究)@Davin:在@Martin的评论中添加:设置READ_COMMITTED\u SHAPSHOT=ON
以启用READ COMMITTED
事务的快照锁定行为。设置此变量将使SQL Server
除了将被覆盖的数据存储在事务日志中之外,还可以将其保存在tempdb
中。非常有用!这证实了@Martin上面所说的,一旦创建了5000个锁,它就会将锁更改为表级别。我如何将更新批处理成5000个块,而不需要不断覆盖?围绕更新进行一个while循环,如果@rowcount<@BatchSize,则中断。除非我读错了您的查询,否则在填充完表_1的所有字段列has data之后,while循环将退出。
DECLARE @BatchSize int;
SET @BatchSize = <Vary this number until you see a table lock taken>;
BEGIN TRAN
UPDATE TOP(@BatchSize) A WITH (UPDLOCK,ROWLOCK)
SET A.field = B.field
FROM Table_1 A
INNER JOIN Table2 B ON A.id = B.id
WHERE A.field IS NULL
AND B.field IS NOT NULL
SELECT
*
FROM
sys.dm_tran_locks
WHERE
[request_session_id] = @@spid
ROLLBACK