【问题标题】:Lock table while inserting插入时锁定表
【发布时间】:2018-10-26 14:13:00
【问题描述】:

我有一个从视图中填充的大表。这样做是因为视图需要很长时间才能运行,并且更容易在表中轻松获取数据。每隔一段时间就会运行一个过程来更新表。

 TRUNCATE TABLE LargeTable

 INSERT INTO LargeTable
 SELECT * 
 FROM viewLargeView
 WITH (HOLDLOCK)

我想在插入时锁定此表,因此如果有人尝试选择一条记录,他们在截断后将不会收到任何记录。我使用的锁似乎锁定了视图而不是表。

有没有更好的方法来解决这个问题?

【问题讨论】:

  • 在插入之前打开事务并在之后关闭它呢?
  • 打开事务时,其他用户可以从表中选择吗?
  • 仅供参考,我建议您使用 DELETE 而不是 TRUNCATE,因为 TRUNCATE 是一个 DDL,而不是像 DELETE 这样的 DML,因此需要更大的权限。另外,如果您将其包装在事务中(这是您问题的正确答案),它们将有效地执行相同的操作。
  • 另外,事务中的 TRUNCATE TABLE 可以在事务的长度内锁定您的数据库元数据,如果它被阻塞可能会导致错误的 juju。如果这是可操作的(非工作时间),那么它可能没问题,但如果它在您有用户与数据库交互时运行,您可能会遇到问题......

标签: sql sql-server tsql locking


【解决方案1】:

确实,您正确的锁定提示会影响源视图。

为了使插入时没有人可以读取表格:

insert into LargeTable with (tablockx)
...

在插入完成之前,您无需执行任何操作来使表格看起来是空的。插入总是在事务中运行,没有其他进程可以读取未提交的行,除非它们明确指定with (nolock)set transaction isolation level read uncommitted。据我所知,没有办法避免这种情况。

【讨论】:

    【解决方案2】:
    BEGIN TRY
     BEGIN TRANSACTION t_Transaction
    
     TRUNCATE TABLE LargeTable
    
     INSERT INTO LargeTable
     SELECT * 
     FROM viewLargeView
      WITH (HOLDLOCK)
    
     COMMIT TRANSACTION t_Transaction
    END TRY 
    BEGIN CATCH
      ROLLBACK TRANSACTION t_Transaction
    END CATCH
    

    【讨论】:

    • 不要认为这会做任何事情。 truncate 不受事务影响,insert all 本身也是事务,即使你没有指定。
    • 实际上 TRUNCATE 回滚了一些警告。见this
    • 据此docs.microsoft.com/en-us/sql/t-sql/statements/… "TRUNCATE TABLE 不能在事务内部运行。"
    • @Emo,仅适用于:“在 Azure SQL 数据仓库和并行数据仓库中,TRUNCATE TABLE 不能在事务内部运行。”
    • 啊,是的,我现在明白了
    猜你喜欢
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-31
    相关资源
    最近更新 更多