Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/email/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 确定锁升级的阈值_Sql_Sql Server_Sql Server 2005 - Fatal编程技术网

Sql 确定锁升级的阈值

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将在什么时候升级对

我有一个大约有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语句的锁定(因为我不希望锁定整个表)

我没有权限运行服务器跟踪以查看锁是如何应用的,因此是否有其他方法可以知道锁将在何时升级以覆盖整个表

谢谢

一旦语句在对象的单个实例上获取了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