SQL Server中的临时表和表变量有什么区别?


390

在SQL Server 2005中,我们可以使用以下两种方式之一创建临时表:

declare @tmp table (Col1 int, Col2 int);

要么

create table #tmp (Col1 int, Col2 int);

两者之间有什么区别?对于@tmp是否仍使用tempdb或内存中是否发生了所有事情,我有不同意见。

在哪一种情况下胜过另一种?



2
有由皮纳尔戴维是一个非常好的写在这里... blog.sqlauthority.com/2009/12/15/...
SAM毅

Answers:


392

临时表(#tmp)和表变量(@tmp)之间有一些区别,尽管使用tempdb并不是其中之一,如下面的MSDN链接中所述。

根据经验,对于中小型数据量和简单使用场景,应使用表变量。(这是一个过于宽泛的准则,当然会有很多例外情况-请参阅下文和后续文章。)

在它们之间进行选择时应考虑以下几点:

  • 临时表是真实表,因此您可以执行诸如CREATE INDEXes等操作。如果您有大量数据,通过索引对其进行访问将更快,那么临时表是一个不错的选择。

  • 通过使用PRIMARY KEY或UNIQUE约束,表变量可以具有索引。(如果要非唯一索引,只需将主键列作为唯一约束中的最后一列。如果没有唯一列,则可以使用标识列。)SQL 2014也具有非唯一索引

  • 表变量不参与事务,并且SELECTs隐含NOLOCK。事务行为可能非常有帮助,例如,如果您想在过程中途回滚,那么在该事务期间填充的表变量仍将被填充!

  • 临时表可能导致存储过程可能经常被重新编译。表变量不会。

  • 您可以使用SELECT INTO创建临时表,该表可以更快地编写(适合临时查询),并且可以让您处理随时间变化的数据类型,因为您无需预先定义临时表结构。

  • 您可以将表变量从函数传递回来,从而使您可以更轻松地封装和重用逻辑(例如,使函数将字符串拆分为任意定界符上的值表)。

  • 在用户定义的函数中使用表变量可以使这些函数得到更广泛的使用(有关详细信息,请参见CREATE FUNCTION文档)。如果要编写函数,则应在临时表上使用表变量,除非另有迫切需要。

  • 表变量和临时表都存储在tempdb中。但是表变量(自2005年起)默认为当前数据库的排序规则,而temp表则采用默认的tempdb(ref)排序规则。这意味着如果使用临时表并且您的数据库排序规则与tempdb的排序规则不同,则应该注意排序规则问题,如果要将临时表中的数据与数据库中的数据进行比较,则会引起问题。

  • 全局临时表(## tmp)是可用于所有会话和用户的另一种临时表。

一些进一步的阅读:


26
表变量可以具有索引。只需创建一个唯一约束,即可自动获得索引。产生巨大的性能差异。(如果不需要唯一索引,只需将实际的主键添加到所需字段的末尾。如果没有,请创建一个标识列)。

7
@Ben And SQL Server 2014允许在表变量上指定
Martin Smith

4
不受事务影响的表变量有时很方便。如果在回滚后有任何要保留的内容,可以将其放在表变量中。
quillbreaker

3
为临时表创建统计信息,这可以改善查询计划,但不能为表变量提供统计信息。删除临时表后,这些统计信息会与临时表的页面一起缓存一段时间,如果重新激活缓存的表可能会不准确。
Michael Green

表变量将默认为用户定义的数据类型的排序规则(如果该列属于用户定义的数据类型)或当前数据库的排序规则,而不是tempdb的默认排序规则。临时表将使用tempdb默认排序规则。请参阅:technet.microsoft.com/zh-cn/library/ms188927.aspx
PseudoToad 2015年

25

仅查看已接受答案中的声明,即表变量不参与日志记录。

似乎一般不真实,有至少在日志记录(数量有什么区别insert/ update/ delete操作表本身虽然我因为发现有这方面的存储过程缓存临时对象,一些小的差异,由于额外的系统表更新)。

我针对以下操作针对a @table_variable#temp表查看了日志记录行为。

  1. 成功插入
  2. 多行插入where语句由于违反约束而回滚。
  3. 更新资料
  4. 删除
  5. 解除分配

所有操作的事务日志记录几乎相同。

表变量版本实际上具有一些额外的日志条目,因为它向sys.syssingleobjrefs基本表中添加了一个条目(后来又从中删除了该条目),但是总体上记录的字节数要少得多,因为表变量的内部名称比#temp表少了236个字节(少118nvarchar字符)。

复制完整脚本(最好在以单用户模式和使用sqlcmd模式启动的实例上运行)

:setvar tablename "@T" 
:setvar tablescript "DECLARE @T TABLE"

/*
 --Uncomment this section to test a #temp table
:setvar tablename "#T" 
:setvar tablescript "CREATE TABLE #T"
*/

USE tempdb 
GO    
CHECKPOINT

DECLARE @LSN NVARCHAR(25)

SELECT @LSN = MAX([Current LSN])
FROM fn_dblog(null, null) 


EXEC(N'BEGIN TRAN StartBatch
SAVE TRAN StartBatch
COMMIT

$(tablescript)
(
[4CA996AC-C7E1-48B5-B48A-E721E7A435F0] INT PRIMARY KEY DEFAULT 0,
InRowFiller char(7000) DEFAULT ''A'',
OffRowFiller varchar(8000) DEFAULT REPLICATE(''B'',8000),
LOBFiller varchar(max) DEFAULT REPLICATE(cast(''C'' as varchar(max)),10000)
)


BEGIN TRAN InsertFirstRow
SAVE TRAN InsertFirstRow
COMMIT

INSERT INTO $(tablename)
DEFAULT VALUES

BEGIN TRAN Insert9Rows
SAVE TRAN Insert9Rows
COMMIT


INSERT INTO $(tablename) ([4CA996AC-C7E1-48B5-B48A-E721E7A435F0])
SELECT TOP 9 ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM sys.all_columns

BEGIN TRAN InsertFailure
SAVE TRAN InsertFailure
COMMIT


/*Try and Insert 10 rows, the 10th one will cause a constraint violation*/
BEGIN TRY
INSERT INTO $(tablename) ([4CA996AC-C7E1-48B5-B48A-E721E7A435F0])
SELECT TOP (10) (10 + ROW_NUMBER() OVER (ORDER BY (SELECT 0))) % 20
FROM sys.all_columns
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE()
END CATCH

BEGIN TRAN Update10Rows
SAVE TRAN Update10Rows
COMMIT

UPDATE $(tablename)
SET InRowFiller = LOWER(InRowFiller),
    OffRowFiller  =LOWER(OffRowFiller),
    LOBFiller  =LOWER(LOBFiller)


BEGIN TRAN Delete10Rows
SAVE TRAN Delete10Rows
COMMIT

DELETE FROM  $(tablename)
BEGIN TRAN AfterDelete
SAVE TRAN AfterDelete
COMMIT

BEGIN TRAN EndBatch
SAVE TRAN EndBatch
COMMIT')


DECLARE @LSN_HEX NVARCHAR(25) = 
        CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 1, 8),2) AS INT) AS VARCHAR) + ':' +
        CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 10, 8),2) AS INT) AS VARCHAR) + ':' +
        CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 19, 4),2) AS INT) AS VARCHAR)        

SELECT 
    [Operation],
    [Context],
    [AllocUnitName],
    [Transaction Name],
    [Description]
FROM   fn_dblog(@LSN_HEX, null) AS D
WHERE  [Current LSN] > @LSN  

SELECT CASE
         WHEN GROUPING(Operation) = 1 THEN 'Total'
         ELSE Operation
       END AS Operation,
       Context,
       AllocUnitName,
       COALESCE(SUM([Log Record Length]), 0) AS [Size in Bytes],
       COUNT(*)                              AS Cnt
FROM   fn_dblog(@LSN_HEX, null) AS D
WHERE  [Current LSN] > @LSN  
GROUP BY GROUPING SETS((Operation, Context, AllocUnitName),())

结果

+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
|                       |                    |                           |             @TV      |             #TV      |                  |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| Operation             | Context            | AllocUnitName             | Size in Bytes | Cnt  | Size in Bytes | Cnt  | Difference Bytes |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| LOP_ABORT_XACT        | LCX_NULL           |                           | 52            | 1    | 52            | 1    |                  |
| LOP_BEGIN_XACT        | LCX_NULL           |                           | 6056          | 50   | 6056          | 50   |                  |
| LOP_COMMIT_XACT       | LCX_NULL           |                           | 2548          | 49   | 2548          | 49   |                  |
| LOP_COUNT_DELTA       | LCX_CLUSTERED      | sys.sysallocunits.clust   | 624           | 3    | 624           | 3    |                  |
| LOP_COUNT_DELTA       | LCX_CLUSTERED      | sys.sysrowsets.clust      | 208           | 1    | 208           | 1    |                  |
| LOP_COUNT_DELTA       | LCX_CLUSTERED      | sys.sysrscols.clst        | 832           | 4    | 832           | 4    |                  |
| LOP_CREATE_ALLOCCHAIN | LCX_NULL           |                           | 120           | 3    | 120           | 3    |                  |
| LOP_DELETE_ROWS       | LCX_INDEX_INTERIOR | Unknown Alloc Unit        | 720           | 9    | 720           | 9    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysallocunits.clust   | 444           | 3    | 444           | 3    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysallocunits.nc      | 276           | 3    | 276           | 3    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syscolpars.clst       | 628           | 4    | 628           | 4    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syscolpars.nc         | 484           | 4    | 484           | 4    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysidxstats.clst      | 176           | 1    | 176           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysidxstats.nc        | 144           | 1    | 144           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysiscols.clst        | 100           | 1    | 100           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysiscols.nc1         | 88            | 1    | 88            | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysobjvalues.clst     | 596           | 5    | 596           | 5    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysrowsets.clust      | 132           | 1    | 132           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysrscols.clst        | 528           | 4    | 528           | 4    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.clst       | 1040          | 6    | 1276          | 6    | 236              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.nc1        | 820           | 6    | 1060          | 6    | 240              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.nc2        | 820           | 6    | 1060          | 6    | 240              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.nc3        | 480           | 6    | 480           | 6    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syssingleobjrefs.clst | 96            | 1    |               |      | -96              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syssingleobjrefs.nc1  | 88            | 1    |               |      | -88              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | Unknown Alloc Unit        | 72092         | 19   | 72092         | 19   |                  |
| LOP_DELETE_ROWS       | LCX_TEXT_MIX       | Unknown Alloc Unit        | 16348         | 37   | 16348         | 37   |                  |
| LOP_FORMAT_PAGE       | LCX_HEAP           | Unknown Alloc Unit        | 1596          | 19   | 1596          | 19   |                  |
| LOP_FORMAT_PAGE       | LCX_IAM            | Unknown Alloc Unit        | 252           | 3    | 252           | 3    |                  |
| LOP_FORMAT_PAGE       | LCX_INDEX_INTERIOR | Unknown Alloc Unit        | 84            | 1    | 84            | 1    |                  |
| LOP_FORMAT_PAGE       | LCX_TEXT_MIX       | Unknown Alloc Unit        | 4788          | 57   | 4788          | 57   |                  |
| LOP_HOBT_DDL          | LCX_NULL           |                           | 108           | 3    | 108           | 3    |                  |
| LOP_HOBT_DELTA        | LCX_NULL           |                           | 9600          | 150  | 9600          | 150  |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysallocunits.clust   | 456           | 3    | 456           | 3    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.syscolpars.clst       | 644           | 4    | 644           | 4    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysidxstats.clst      | 180           | 1    | 180           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysiscols.clst        | 104           | 1    | 104           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysobjvalues.clst     | 616           | 5    | 616           | 5    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysrowsets.clust      | 136           | 1    | 136           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysrscols.clst        | 544           | 4    | 544           | 4    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysschobjs.clst       | 1064          | 6    | 1300          | 6    | 236              |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.syssingleobjrefs.clst | 100           | 1    |               |      | -100             |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | Unknown Alloc Unit        | 135888        | 19   | 135888        | 19   |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_INTERIOR | Unknown Alloc Unit        | 1596          | 19   | 1596          | 19   |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysallocunits.nc      | 288           | 3    | 288           | 3    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.syscolpars.nc         | 500           | 4    | 500           | 4    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysidxstats.nc        | 148           | 1    | 148           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysiscols.nc1         | 92            | 1    | 92            | 1    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysschobjs.nc1        | 844           | 6    | 1084          | 6    | 240              |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysschobjs.nc2        | 844           | 6    | 1084          | 6    | 240              |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysschobjs.nc3        | 504           | 6    | 504           | 6    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.syssingleobjrefs.nc1  | 92            | 1    |               |      | -92              |
| LOP_INSERT_ROWS       | LCX_TEXT_MIX       | Unknown Alloc Unit        | 5112          | 71   | 5112          | 71   |                  |
| LOP_MARK_SAVEPOINT    | LCX_NULL           |                           | 508           | 8    | 508           | 8    |                  |
| LOP_MODIFY_COLUMNS    | LCX_CLUSTERED      | Unknown Alloc Unit        | 1560          | 10   | 1560          | 10   |                  |
| LOP_MODIFY_HEADER     | LCX_HEAP           | Unknown Alloc Unit        | 3780          | 45   | 3780          | 45   |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.syscolpars.clst       | 384           | 4    | 384           | 4    |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.sysidxstats.clst      | 100           | 1    | 100           | 1    |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.sysrowsets.clust      | 92            | 1    | 92            | 1    |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.sysschobjs.clst       | 1144          | 13   | 1144          | 13   |                  |
| LOP_MODIFY_ROW        | LCX_IAM            | Unknown Alloc Unit        | 4224          | 48   | 4224          | 48   |                  |
| LOP_MODIFY_ROW        | LCX_PFS            | Unknown Alloc Unit        | 13632         | 169  | 13632         | 169  |                  |
| LOP_MODIFY_ROW        | LCX_TEXT_MIX       | Unknown Alloc Unit        | 108640        | 120  | 108640        | 120  |                  |
| LOP_ROOT_CHANGE       | LCX_CLUSTERED      | sys.sysallocunits.clust   | 960           | 10   | 960           | 10   |                  |
| LOP_SET_BITS          | LCX_GAM            | Unknown Alloc Unit        | 1200          | 20   | 1200          | 20   |                  |
| LOP_SET_BITS          | LCX_IAM            | Unknown Alloc Unit        | 1080          | 18   | 1080          | 18   |                  |
| LOP_SET_BITS          | LCX_SGAM           | Unknown Alloc Unit        | 120           | 2    | 120           | 2    |                  |
| LOP_SHRINK_NOOP       | LCX_NULL           |                           |               |      | 32            | 1    | 32               |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| Total                 |                    |                           | 410144        | 1095 | 411232        | 1092 | 1088             |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+

1
+1只是出于好奇(而且有点书呆子)。这个问题已经很老了(2008年8月),所以它是关于SQL 2005的。现在我们是在2011年(年底),而最新的SQL是2008 R2和Denali beta。您使用了哪个版本?
xanatos 2011年

2
@xanatos-2008。在2005年,表变量实际上处于劣势,因为INSERT ... SELECT它没有被最小记录,因此您不能SELECT INTO ... 创建表变量。
马丁·史密斯,

1
感谢@MartinSmith,更新了我的答案以删除有关日志记录的声明。
罗里2015年


17

@wcm-实际上是要选择表变量,而不仅仅是Ram-它可以部分存储在磁盘上。

临时表可以具有索引,而表变量只能具有主索引。如果速度是一个问题,表变量可以更快,但是显然如果有很多记录,或者需要搜索聚集索引的临时表,那么临时表会更好。

好背景文章


2
好的背景文章+1。我将删除我的答案,因为修改它不会留下太多,而且已经有很多好的答案
wcm 2010年

12
  1. 临时表:临时表易于创建和备份数据。

    表变量:但是,当我们通常创建普通表时,表变量会涉及工作量。

  2. 临时表:临时表结果可由多个用户使用。

    表变量:但是表变量只能由当前用户使用。 

  3. 临时表:临时表将存储在tempdb中。它将产生网络流量。当临时表中有大量数据时,它就必须跨数据库工作。将存在性能问题。

    表变量:但是,表变量将在某些数据中存储在物理内存中,然后在大小增加时将其移至tempdb。

  4. 临时表:临时表可以执行所有DDL操作。它允许创建索引,删除,更改等。

    表变量:表变量不允许执行DDL操作。但是table变量只允许我们创建聚簇索引。

  5. 临时表:临时表可用于当前会话或全局会话。这样,多用户会话就可以利用表中的结果。

    表变量:但是表变量可以在该程序中使用。(存储过程)

  6. 临时表:临时变量不能使用事务。当我们使用临时表进行DML操作时,它可以回滚或提交事务。

    表变量:但是我们不能对表变量执行此操作。

  7. 临时表:函数不能使用临时变量。此外,我们无法在函数中执行DML操作。

    表变量:但是该函数允许我们使用表变量。但是使用表变量,我们可以做到这一点。

  8. 临时表:当我们为每个后续调用使用temp变量时,存储过程将进行重新编译(不能使用相同的执行计划)。

    表变量:表变量不会那样做。



7

另一个主要区别是表变量不像临时表那样具有列统计信息。这意味着查询优化器不知道表变量中有多少行(它猜测为1),如果表变量实际上具有大量行,则可能导致生成高度非最佳的计划。


2
表中的rowssys.partitions是为表变量维护的,因此它实际上知道表中有多少行。使用可以看到这一点OPTION (RECOMPILE)。但是缺少列统计信息意味着它无法估计特定的列谓词。
马丁·史密斯,

7

引用来自;专业SQL Server 2012内部和故障排除

统计 临时表和表变量之间的主要区别在于,不会在表变量上创建统计信息。这有两个主要结果,首先是查询优化器对表变量中的行数使用固定估计,而不考虑其包含的数据。此外,添加或删除数据不会改变估计值。

指标尽管可以创建约束,但无法在表变量上创建索引。这意味着通过创建主键或唯一约束,您可以在表变量上具有索引(因为创建这些索引是为了支持约束)。即使您有约束,因此索引也将具有统计信息,但编译查询时将不使用索引,因为它们在编译时将不存在,也不会导致重新编译。

模式修改可以在临时表上进行模式修改,但不能在表变量上进行模式修改。尽管可以在临时表上进行模式修改,但请避免使用它们,因为它们会导致重新编译使用该表的语句。

临时表与表变量

表变量未在内存中创建

常见的误解是表变量是内存结构,因此其执行速度要比临时表快。多亏了一个名为sys的DMV。dm _ db _ session _ space _ usage,它按会话显示tempdb的使用情况,您可以证明并非如此。重新启动SQL Server清除DMV后,运行以下脚本来确认您的会话_ id为用户_对象_分配_页面_ count返回0:

SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;

现在,您可以通过运行以下脚本来创建临时表,并用一行填充并填充一行,以检查临时表使用了多少空间:

CREATE TABLE #TempTable ( ID INT ) ;
INSERT INTO #TempTable ( ID )
VALUES ( 1 ) ;
GO
SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;

我服务器上的结果表明该表在tempdb中分配了一页。现在运行相同的脚本,但是这次使用表变量:

DECLARE @TempTable TABLE ( ID INT ) ;
INSERT INTO @TempTable ( ID )
VALUES ( 1 ) ;
GO
SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;

使用哪一个?

是否使用临时表或表变量应通过全面的测试来确定,但是最好将临时 表作为默认表,因为 出错的情况要少得多

我已经看到客户使用表变量开发代码,因为他们处理的是少量的行,并且比临时表要快,但是几年后,表变量中有成千上万的行,并且性能非常差,因此请在做出决定时尝试进行一些容量规划!


在被上表变量创建事实统计,看stackoverflow.com/questions/42824366/...
裕丰沉

4

另一个区别:

表var只能从创建它的过程中的语句访问,而不能从该过程调用的其他过程或嵌套的动态SQL(通过exec或sp_executesql)访问。

另一方面,临时表的范围包括称为过程的代码和嵌套的动态SQL。

如果您的过程创建的表必须可以从其他调用的过程或动态SQL访问,则必须使用临时表。在复杂情况下,这可能非常方便。


2

Temporary Tables (##temp/#temp)和之间的差异Table Variables (@table)如下:

  1. Table variable (@table)在中创建memory。而在Temporary table (##temp/#temp)中创建了一个tempdb database。但是,如果存在内存压力,则属于表变量的页面可能会被推送到tempdb。

  2. Table variables不能参与transactions, logging or locking。这使@table faster then #temp。因此表变量要比临时表快。

  3. Temporary table允许模式修改与有所不同Table variables

  4. Temporary tables在创建的例程以及子例程中都可见。而表变量仅在创建的例程中可见。

  5. Temporary tables允许使用,CREATE INDEXesTable variables不允许使用,CREATE INDEX而是可以使用进行索引Primary Key or Unique Constraint


1

还请考虑您经常可以用派生表替换这两个表,而派生表也可能更快。但是,与所有性能调整一样,只有针对实际数据进行的实际测试才能告诉您针对特定查询的最佳方法。


1

令我惊讶的是,没有人提到这两者之间的关键区别是temp表支持并行插入,而table变量不支持。您应该能够看到与执行计划的区别。这是第9频道SQL Workshops的视频

这也解释了为什么您应该对较小的表使用临时变量,否则使用临时表,如SQLMenace之前回答的那样

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.