【问题标题】:Truncate/Clear table variable in SQL Server 2008SQL Server 2008 中的截断/清除表变量
【发布时间】:2014-02-26 15:52:22
【问题描述】:

是否可以在 SQL Server 2008 中截断或清除表变量?

declare @tableVariable table
(
   id int, 
   value varchar(20)
)    

while @start <= @stop    
begin    
    insert into @tableVariable(id, value) 
        select id
            , value 
        from xTable 
        where id = @start
    
    --Use @tableVariable 

    --@tableVariable should be flushed out of 
    -- old values before inserting new  values

    set @start = @start + 1 
end 

【问题讨论】:

  • 您到底想完成什么?如果您只是要再次冲洗它们,为什么还要插入任何东西?
  • 插入在这里只是象征性的。实际操作要复杂得多,涉及到很多其他的表
  • 有评论--Use @tableVariable 估计是用来做一些计算的,没有附上
  • 是的.. 它将用于一些计算.. 请不要与 USE 混淆

标签: sql sql-server tsql


【解决方案1】:

删除所有内容

DELETE FROM @tableVariable

【讨论】:

  • 更好的答案是“你不能”,然后解释替代方案。
  • 这将起作用,但请记住,正如@Martin%20Smith 在下面指出的那样,此删除将被记录。如果变量中有很多行,或者这条SQL会定期执行,这可能会出现问题。
【解决方案2】:

不,您不能TRUNCATE 表变量,因为它不是物理表。删除它会更快。请参阅Aaron Bertrand 的答案。

【讨论】:

  • 不能截断再快不过了。只有删除选项。
【解决方案3】:

如果您碰巧在您的@Table 变量中也有一个身份字段(例如i int (1,1))和您想重新使用此表(即使您在循环中重新声明它)它仍在范围内,也无法重新设置它。

见:Table Variable Identity Column

在这些情况下最好使用#TempTable - 然后您可以截断或使用 DBCC 重新设置种子。
您将通过 Truncate 获得性能改进并且能够创建额外的索引。
我认为经验法则是,如果您要使用 DELETE @VariableTable 删除所有内容,那么您已经引入了一种代码气味,表明您应该使用 #TempTableTRUNCATE

【讨论】:

    【解决方案4】:

    表变量不支持TRUNCATE 语法 - 截断它们的唯一方法是隐式地让它们超出范围。

    临时表和表变量can be cached 在存储过程中使用时很可能会在截断后使用相同的表变量,而不是实际的删除和创建

    CREATE PROC dbo.foo @start INT
    AS
      BEGIN
          DECLARE @tableVariable TABLE (
            id    INT,
            value VARCHAR(20))
    
          INSERT INTO @tableVariable
                      (id,
                       value)
          SELECT id,
                 value
          FROM   xTable
          WHERE  id = @start;
      --Use @tableVariable 
      END
    
    GO
    
    WHILE @start <= @stop
      BEGIN
          EXEC dbo.foo @start
    
          SET @start = @start + 1
      END 
    

    当然,更简单的替代方法是改用#temp 表,因为它直接支持TRUNCATE

    表变量和临时表上的 DML 写入 tempdb 事务日志。是否值得切换到TRUNCATE 而不是DELETE 取决于所涉及的数据大小。 TRUNCATE 只会记录页面释放。 DELETE 将记录实际删除的值。两者之间的另一个区别是TRUNCATE 会从表中释放最后一页,而DELETE 不会。如果在每次循环迭代中只插入和删除少量数据,则记录已删除行的开销can be less 比不断释放和重新分配表中的单个页面的开销。

    相反,如果您将在每次迭代中插入和删除大量数据,您可能会发现TRUNCATE 不仅使删除所有行的操作更加高效,而且also can benefit the subsequent insert statement

    【讨论】:

    • 您可以使用DELETE FROM @tableVariable,如已接受的答案中所述,获得与TRUNCATE TABLE 基本等效的功能(除了日志记录 - 这可能肯定是如果变量中有很多行,或者创建变量的 SQL 经常运行,则会出现问题)。
    • @BartRead - TRUNCATE 在所有行中优于 DELETE 的优势是事务日志记录。
    【解决方案5】:

    这是 Table 变量的其他限制。大多数情况下,我们使用 Truncate 命令需要重置表的标识。假设您将值插入光标内的表变量中,并且您需要清除表变量,因为每次插入都会填充新的标识。在这种情况下,我们需要使用#temp 为每次获取游标获取新标识

    【讨论】:

      【解决方案6】:
      --Usage: exec sp_truncateifexists tablename
      CREATE PROCEDURE sp_truncateifexists
          @tableVariable nvarchar(200)
      AS
      BEGIN
          IF EXISTS (
              SELECT 1 
              FROM INFORMATION_SCHEMA.TABLES 
              WHERE TABLE_NAME = @tableVariable )
          BEGIN
              DECLARE @query nvarchar(250)
              SET @query = 'TRUNCATE TABLE ' + @tableVariable 
              EXECUTE (@query)
          END
      END
      GO
      

      如果您以后不需要这些表格,请记住使用#temp tables

      【讨论】:

        【解决方案7】:

        我知道这是一个老问题,但我想出了一个办法。 我们有数百万行的表,由于事务日志空间,不想删除它们。

        创建一个您传入要截断的表名的过程,该过程将创建另一个执行截断然后删除过程的过程。

        USE [My_Database]
        GO
        /****** Object:  StoredProcedure [dbo].[ClearOutTable_p1]    Script Date: 23/09/2015 09:03:14 ******/
        SET ANSI_NULLS ON
        GO
        SET QUOTED_IDENTIFIER ON
        GO
        
        -- =============================================
        -- Author:      Oraclebhoy
        -- Create date: 23/09/2015
        -- Description: 
        -- 
        -- removes the content of the table passed in through the parameter
        -- =============================================
        create procedure [dbo].[ClearOutTable_p1]
        @tablename varchar(max)
        as
        
        -- CREATE THE TRUNCATE STATEMENT PASSING IN TABLE VARIABLE
            declare @truncatesql varchar(max)
            set @truncatesql = 'truncate table ' + @tablename
        
        -- IF PROCEDURE EXISTS DROP
            if exists (select name from sys.all_objects where name = 'ClearOutTable_TEMP'and type = 'P')
                begin
                    drop procedure [dbo].[ClearOutTable_TEMP]
                end
        
        -- CREATE TEMP PROCEDURE
            exec ('create procedure [dbo].[ClearOutTable_TEMP]
            as
            '+@truncatesql+'')
        
        -- EXECUTE THE PROCEDURE
            exec [dbo].[ClearOutTable_TEMP]
        
        -- DROP THE PROCEDURE
            drop procedure [dbo].[ClearOutTable_TEMP]
        

        希望这会有所帮助。

        【讨论】:

        • 为什么需要创建一个单独的过程来执行截断?鉴于您不断创建和删除具有相同名称的过程,您将如何确保并发性?最重要的是,您将如何将其用于table variables
        猜你喜欢
        • 2012-11-18
        • 2011-02-08
        • 1970-01-01
        • 2015-07-08
        • 1970-01-01
        • 2017-08-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-29
        相关资源
        最近更新 更多