SQL Server 2008 中的截断/清除表变量

Posted

技术标签:

【中文标题】SQL Server 2008 中的截断/清除表变量【英文标题】:Truncate/Clear table variable in SQL 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 混淆 【参考方案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?

以上是关于SQL Server 2008 中的截断/清除表变量的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 2008截断事务日志

sql server 2008 日志文件已经到了最大值,还会记录日志吗

二进制 Blob 被截断为 8000 字节 - SQL Server 2008 / varbinary(max)

sql server 2008 清除日志

sql server 2008 r2 日志文件过大怎么清除

sql server 2008清除日志