【问题标题】:Using ROWLOCK in an INSERT statement (SQL Server)在 INSERT 语句中使用 ROWLOCK (SQL Server)
【发布时间】:2010-05-18 12:45:39
【问题描述】:

在复制大量数据并将其插入同一个表的插入语句上使用 ROWLOCK 是否明智?

例如)

INSERT INTO TABLE with (rowlock) (id, name) 
   SELECT newid, name 
   FROM TABLE with (nolock) 
   WHERE id = 1

是否有人对如何改进此语句提出建议,正如我所见,当 SQL Server 忙碌时,它将以 SQL Server 返回的超时查询结束。

【问题讨论】:

  • 您要插入的表是新表,还是包含现有数据的现有表?
  • 你能解释一下你为什么这样做吗?另外,你为什么使用 (nolock) 提示?

标签: sql-server


【解决方案1】:

您最好先将子查询结果存储在临时表中,然后再插入。

【讨论】:

  • 为什么会这样?这将有效地使插入量增加一倍。
【解决方案2】:

好吧,不能在 INSERT 语句中使用 WITH (NOLOCK) 表提示。见https://docs.microsoft.com/en-us/sql/t-sql/statements/insert-transact-sql#arguments

如果在任何给定时间只有一个进程或应用程序在同一个表中复制数据,那么各种事务隔离级别对您没有多大帮助。它们旨在隔离(分离)不同的事务,并且对单个事务没有影响。

此外,通常最好将查询优化委托给 SQL Server,因为查询的所有必要元素都是已知的,并且 - 我假设 - 没有针对同一个表的其他竞争查询,这可能会搞砸优化查询执行计划。

【讨论】:

    【解决方案3】:

    如果您要插入大量数据并且遇到读取器/写入器问题(锁定、超时),您可能应该将您的插入分成几部分(前 100 个或其他),直到您完成所有数据。如果不这样做,即使声明了行锁,也可能会发生锁升级,在这种情况下,SQL Server 会在您插入数据时获取表锁。

    另一个不错的选择是使用 SNAPSHOT 隔离,如果您有足够的可用空间,这将是完美的。 对于第一个选项,请阅读此处Q

    http://support.microsoft.com/kb/323630

    【讨论】:

      【解决方案4】:

      如果您要插入大量数据,例如 1000 行或更多,那么您可以考虑使用临时表或表变量。首先将行插入到临时表或变量中,然后执行 insert into final_table select * from temp table 将工作得很好。如果您需要更多行,则只需将插入内容放在游标内,然后每 1000 行迭代一次,直到完成总行数。

      对于更复杂的插入,如果你需要保留标识键,或者将它们用作其他表中的引用键,你可以将整个存储过程放在一个事务中,并从最终表中计算最后使用的标识键,并将其用作临时表的标识键的第一个值,或设置标识关闭

      【讨论】:

        猜你喜欢
        • 2013-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-09
        • 2017-12-19
        • 2015-11-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多