当我更新/插入单行时应该锁定整个表吗?

时间:2010-02-11 21:54:55

标签: sql-server locking

我有两个长时间运行的查询,它们都在事务上并访问同一个表,但在这些表中完全分开的行。这些查询还会根据这些查询执行一些更新和插入。

当它们同时运行时,它们会遇到某种类型的锁,并且它会阻止任务完成并在更新其中一行时锁定。我正在对正在读取的行使用独占行锁,并且在进程上显示的锁是lck_m_ix锁。

两个问题:

  1. 当我更新/插入一行时,它会锁定整个表吗?
  2. 可以采取哪些措施来解决这类问题?

4 个答案:

答案 0 :(得分:21)

通常没有,但它取决于(最常用于SQL Server的答案!)

SQL Server必须以某种方式锁定事务中涉及的数据。在执行修改时,它必须锁定表本身中的数据以及任何受影响索引的数据。为了提高并发性,服务器可能决定使用几种锁定“粒度”,以允许多个进程运行:行锁,页锁和表锁是常见的(还有更多)。哪种锁定程序在起作用取决于服务器如何决定执行给定的更新。使事情变得复杂的是,还有一些锁的分类,如shared,exclusive和intent exclusive,它们控制是否可以读取和/或修改锁定的对象。

根据我的经验,SQL Server主要使用页锁来更改表的一小部分,如果某个表的大部分(来自统计数据)受到影响,则超过某个阈值将自动升级为表锁。更新或删除。我们的想法是,锁定表(一个锁)比获取和管理数千个单独的行或页锁以进行大更新更快。

要查看特定情况下发生的情况,您需要查看查询逻辑,并在您的东西运行时检查sys.dm_tran_locks,sys.dm_os_waiting_tasks或其他DMV中的锁定/阻塞条件。您可能希望通过每个流程中的哪个步骤来发现究竟被锁定的内容,以发现为什么会阻止另一个流程。

答案 1 :(得分:19)

简短版本:

  1. 没有
  2. 修复您的代码。
  3. 长版:

    LCK_M_IX是意图锁,意味着该操作将对从属元素进行X锁定。例如。更新表中的行时,操作表在锁定X正在更新/插入/删除的行之前对表执行IX锁定。意图锁是处理层次结构的常用策略,例如表/页/行,因为锁管理器无法理解请求锁定的资源的物理结构(即,它无法知道页P1上的X锁与不兼容由于R1包含在P1中,因此在行R1上进行S锁定。有关详细信息,请参阅Lock Modes

    您看到意图锁争用的事实意味着您正在尝试获取高级对象锁,例如表锁。您需要分析被阻止请求的源代码(请求锁定与LCK_M_IX不兼容的源代码)并删除对象级别锁定请求的原因。这意味着什么将取决于你的源代码,我不知道你在那里做什么。我的猜测是你使用了错误的锁定提示。

    更通用的方法是依靠SNAPSHOT ISOLATION。但是,这很可能无法解决您所看到的问题,因为快照隔离只会使行级争用问题受益,而不是请求表锁的应用程序。

答案 2 :(得分:11)

使用交易的常见目的:尽可能保持简短和甜蜜。我从问题中的措辞中得知你正在开展交易,然后做各种各样的事情,其中​​一些需要很长时间。然后期望多个用户能够同时运行相同的代码。不幸的是,如果您在该组代码的开头执行插入,那么在提交或回滚之前执行其他40个操作,则该插入可能会阻止其他所有人运行相同类型的插入,从而实际上将您的操作从免费为所有人。

找出每个查询正在做什么,以及您是否获得了您不希望的锁定升级。只是因为你对查询说WITH(ROWLOCK)并不意味着SQL Server能够遵守...如果你触及多个索引,索引视图,持久计算列等等那么你的行锁有多种原因可能没有任何水。您可能在事务中稍后会花费比您想象的更长的时间,也许您没有意识到事务中涉及的所有对象(不仅仅是当前正在运行的语句)的锁定可以保留交易的持续时间。

答案 3 :(得分:1)

不同的数据库具有不同的锁定机制,但SQL Server和Oracle之类的锁定机制具有不同的锁定类型。

SQL Server上的默认设置似乎是悲观的页面锁定 - 所以如果你有少量的记录,那么所有这些记录都可能被锁定。

大多数数据库在运行脚本时都不应该锁定,所以我想知道你是否可能在没有事务的情况下同时运行多个查询。