带#的临时表和带@的表有什么区别

本文探讨了SQL Server中表变量(@test)与临时表(#test)的不同之处。表变量存在于内存中,适用于函数、存储过程及批处理,拥有明确定义的作用域,而在其作用域结束后自动清除。相比之下,临时表存在于tempdb数据库空间中,支持更多的数据库操作如索引建立。文章还介绍了表变量的优点及其在存储过程中的应用。

以下为代码部分:
declare @test table(id int , name varchar(10))
create table #test(id int , name varchar(10))

@test也算是临时表吗,和#test有什么区别

我发现的一点是@test不能在上面建索引而#test能

答:
@test是表变量,存在于内存中;#是临时表,存在于tempdb数据库空间。
可将函数和变量声明为 table 类型。table 变量可用于函数、存储过程和批处理中。

尽可能使用表变量而不使用临时表。table 变量有以下优点:

table 变量的行为类似于局部变量,有明确定义的作用域。该作用域为声明该变量的函数、存储过程或批处理。
在其作用域内,table 变量可像常规表那样使用。该变量可应用于 SELECT、INSERT、UPDATE 和 DELETE 语句中用到表或表的表达式的地方。但是,table 不能用在下列语句中:

INSERT INTO table_variable EXEC 存储过程。 (这个是错的)

SELECT select_list INTO table_variable 语句。 (这个是错的) 用#tbl 就OK

在定义 table 变量的函数、存储过程或批处理结束时,自动清除 table 变量。

在存储过程中使用表变量与使用临时表相比,减少了存储过程的重新编译量。


涉及表变量的事务只在表变量更新期间存在。这样就减少了表变量对锁定和记录资源的需求。
不支持在表变量之间进行赋值操作。另外,由于表变量作用域有限,并且不是持久数据库的一部分,因而不受事务回滚的影响。
表变量作为一种特殊的数据类型,用于存储结果集以供后续处理。该数据类型主要用于临时存储一组行,这些行将作为表值函数的结果集返回。


本文转自:Asp+Access+Sql 开发 -爬坡者

本文链接:http://www.papozhe.com/Asp/ASP-sql-temptable.html

<think>嗯,我现在需要解释SQL Server存储过程中@#临时表区别。让我先回忆一下自己之前学过的内容,然后逐步理清楚。 首先,临时表在SQL Server中确实有两种,一种是名字前面#的,另一种是@的。我记得#的是局部临时表,而@的是变量。不过可能这里用户问的是临时表变量之间的区别,还是说还有其他情况? 让我先确认一下两者的定义。局部临时表,也就是以#开头的,它们存在于tempdb数据库中,并且只在当前会话或作用域中存在。当存储过程执行完毕后,或者会话结束,这些会被自动删除。而变量,也就是以@开头的变量,它们的作用域更像普通的变量,只在定义的批处理或存储过程中存在,但同样存储在tempdb中。 那它们的区别可能包括存储位置、作用域、性能、事务处理等方面。比如,临时表#)可以创建索引,而变量(@)可能不行,或者只能在声明时定义主键?或者是否支持统计信息? 另外,关于事务方面,变量的事务作用域可能更小,比如在事务回滚时,变量的数据不会回滚,而临时表会?这点我记得不太清楚,需要确认。 还有性能差异。当数据量较小时,变量可能更快,因为它们不产生日志,或者产生的日志较少。而临时表在处理大数据量时可能更高效,因为它们可以有统计信息,帮助优化器选择更好的执行计划。但这也可能取决于具体情况,比如是否重建索引或统计信息是否更新。 此外,变量在存储过程执行完毕后会自动清理,而临时表可能在会话结束后才被删除,或者在嵌套存储过程中,临时表可能被其他嵌套的存储过程访问到,而变量只能在当前作用域中使用。 还有一点,变量不能使用ALTER TABLE语句修改结构,只能在声明时定义结构。而临时表可以使用ALTER TABLE添加列或索引。 比如,创建临时表的话,可以使用CREATE TABLE #Temp (ID INT),然后可以ALTER TABLE #Temp ADD Name VARCHAR(50)。而变量声明的时候必须定义好结构,DECLARE @Temp TABLE (ID INT),之后不能再修改结构。 在存储过程中,如果多次调用存储过程,临时表是否会被重用或者冲突?比如,如果存储过程A创建了#Temp,当同时多个会话执行A时,每个会话会有自己的#Temp,因为局部临时表在会话间是隔离的。而变量则是在每个存储过程的执行实例中独立存在。 还有,临时表可以跨作用域访问,比如在动态SQL中创建临时表,之后在外部可以访问吗?可能需要用全局临时表##),但这里讨论的是局部临时表#。而变量在动态SQL中可能无法访问,因为它们的作用域仅限于当前批处理。 此外,关于锁并发,临时表可能会有更多的锁,而变量可能因为不被其他会话访问,所以锁的开销较小。 总结一下,可能的区别点包括: 1. 作用域:变量@仅在当前批处理、存储过程或函数中有效;临时表#在当前会话中的存储过程、函数等中有效,直到会话结束或显式删除。 2. 存储位置:两者都存储在tempdb中,但临时表的结构数据更持久一些。 3. 事务处理:变量的事务仅影响数据操作的原子性,但数据变更在事务回滚时不会被撤销;临时表的变更会受事务影响,回滚时会撤销。 4. 统计信息:临时表会维护统计信息,优化器能生成更好的执行计划;变量没有统计信息,优化器假设其只有一行数据,可能导致性能问题。 5. 索引:临时表可以创建索引,变量只能在声明时定义主键或唯一约束。 6. 结构修改:临时表可以ALTER,变量不行。 7. 并发性:变量更适合小数据量,临时表适合大数据量或复杂查询。 8. 性能:变量通常更快,但数据量大时可能不如临时表高效。 9. 动态SQL:在动态SQL中访问变量可能有限制,而临时表可以在同一会话的动态SQL中使用。 现在需要验证这些观点是否正确。例如,关于事务回滚的部分,变量的数据变更是否真的不受事务回滚影响?比如,如果在一个事务中插入变量,然后回滚,插入的数据是否还存在? 测试一下: BEGIN TRAN DECLARE @t TABLE (ID INT) INSERT INTO @t VALUES(1) ROLLBACK SELECT * FROM @t 此时,应该还能查到ID=1的记录吗?根据之前的理解,变量的事务不会回滚,所以即使回滚了,数据还在。而临时表的话: BEGIN TRAN CREATE TABLE #t (ID INT) INSERT INTO #t VALUES(1) ROLLBACK SELECT * FROM #t 此时,ROLLBACK会回滚CREATE TABLEINSERT,所以#t可能不存在,或者数据被回滚? 这里可能需要注意,CREATE TABLE在事务中被回滚的话,临时表会被删除,因此ROLLBACK之后查询#t会报错对象不存在。但如果是已经存在的临时表,在事务中插入数据,回滚的话数据会被撤销? 例如,假设先创建临时表,然后在事务中插入: CREATE TABLE #t (ID INT) BEGIN TRAN INSERT INTO #t VALUES(1) ROLLBACK SELECT * FROM #t 此时,ROLLBACK会导致INSERT被撤销,所以临时表中的数据会被删除,结果为空。 而变量的事务回滚是否影响数据?可能变量的数据变更不会被回滚。例如: DECLARE @t TABLE (ID INT) BEGIN TRAN INSERT INTO @t VALUES(1) ROLLBACK SELECT * FROM @t 此时,SELECT应该返回1,因为变量的插入操作不受事务回滚的影响。这说明变量的事务行为与临时表不同,这是两者的一个重要区别。 此外,关于统计信息,临时表的查询优化器会使用统计信息来估计行数,而变量则假设只有1行(在旧版本的SQL Server中可能如此,而新版本可能根据实际数据量调整)。例如,当变量中有很多行时,优化器可能选择不合适的执行计划,导致性能问题。 还有,关于索引,变量只能在声明时定义主键或唯一约束,而临时表可以在创建后添加索引。例如: DECLARE @t TABLE (ID INT PRIMARY KEY) -- 允许 CREATE TABLE #t (ID INT) CREATE INDEX IX_ID ON #t(ID) -- 允许 而变量不能在声明后添加索引。 再比如,临时表可以使用SELECT INTO语句创建,而变量不行。例如: SELECT * INTO #temp FROM SomeTable -- 可以 SELECT * INTO @temp FROM SomeTable -- 错误 变量必须通过DECLARE语句定义结构。 此外,关于存储过程中的重入问题,如果存储过程被多个会话同时调用,每个会话的临时表#是独立的,而变量同样在每个会话中是独立的实例,不会互相干扰。 总结下来,两者的主要区别包括作用域、事务行为、统计信息、索引支持、结构修改能力以及性能优化方面的差异。在应用场景上,变量适合小数据量、不需要复杂查询优化的情况,而临时表适合大数据量或需要索引、统计信息支持的情况。</think>在SQL Server存储过程中,`@``#`分别示**变量****局部临时表**,两者在作用域、性能、事务行为等方面有显著差异。以下是具体区别: --- ### 1. **作用域** - **变量(`@`)** - 作用域仅限于当前批处理、存储过程或函数。 - 超出定义范围后自动释放,无需手动删除。 ```sql DECLARE @TempTable TABLE (ID INT, Name VARCHAR(50)); ``` - **局部临时表(`#`)** - 作用域为当前会话(Session),在会话结束或显式删除时释放。 - 在嵌套存储过程中可被调用,或在同一会话的后续SQL中访问。 ```sql CREATE TABLE #TempTable (ID INT, Name VARCHAR(50)); ``` --- ### 2. **存储位置** - 两者均存储在`tempdb`中,但管理方式不同: - **变量**:更像变量,生命周期短,通常不记录事务日志。 - **临时表**:行为接近物理,支持事务日志统计信息。 --- ### 3. **事务行为** - **变量** - 数据修改(如`INSERT`/`UPDATE`)**不受事务回滚影响**。例如: ```sql BEGIN TRANSACTION INSERT INTO @TempTable VALUES(1, &#39;Alice&#39;); ROLLBACK TRANSACTION -- 变量中仍会保留插入的数据 ``` - **临时表** - 数据修改**受事务控制**,回滚会撤销变更: ```sql BEGIN TRANSACTION INSERT INTO #TempTable VALUES(1, &#39;Alice&#39;); ROLLBACK TRANSACTION -- 临时表中的数据被回滚 ``` --- ### 4. **索引与统计信息** - **变量** - 只能在声明时定义主键或唯一约束,无法创建非聚集索引。 - 优化器默认假设变量仅有**1行数据**,可能导致执行计划不优(尤其是大数据量时)。 - **临时表** - 支持创建索引、统计信息,优化器能生成更高效的执行计划。 - 适合复杂查询大数据量场景。 ```sql CREATE INDEX IX_ID ON #TempTable(ID); -- 允许 ``` --- ### 5. **结构修改** - **变量** - 声明后无法修改结构(如新增列)。 - **临时表** - 支持`ALTER TABLE`操作: ```sql ALTER TABLE #TempTable ADD Age INT; -- 允许 ``` --- ### 6. **性能对比** - **变量** - 适合小数据量(如数百行),无需事务控制时性能更优。 - 不产生重编译(Recompile),减少计划缓存开销。 - **临时表** - 适合大数据量或复杂查询,统计信息索引能提升效率。 - 频繁使用可能导致`tempdb`争用。 --- ### 7. **动态SQL中的访问** - **变量** - 无法直接在动态SQL中访问(需通过参数传递)。 - **临时表** - 可在同一会话的动态SQL中直接使用。 --- ### 总结:如何选择? | **场景** | **推荐类型** | |-------------------------|--------------------| | 小数据量、简单逻辑 | 变量(`@`) | | 大数据量、需要索引或统计 | 局部临时表(`#`) | | 需跨作用域或动态SQL访问 | 局部临时表(`#`) | | 事务回滚需撤销数据变更 | 局部临时表(`#`) | 通过合理选择,可以显著优化存储过程的性能可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值