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 删除所有内容
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
删除所有内容,那么您已经引入了一种代码气味,表明您应该使用 #TempTable
和 TRUNCATE
。
【讨论】:
【参考方案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 日志文件已经到了最大值,还会记录日志吗