SQL2005,SQL2008使用临时表@table 的效率好低!

时间:2021-07-07 13:28:49
引用人家的例子!
sql 语句一: 
declare @indextable table(base_card varchar(20),pcount int,last_updated datetime) 
insert @indextable(base_card,pcount,last_updated) 
select b.base_card,count(*) as pcount,max(last_updated) as last_updated from iteminfo a  join BaseInfo b on a.base_id=b.base_id join card c on b.base_card=c.card_no where c.code_agen=1105 group by b.base_card 
select * from @indextable 

sql 语句二: 

DROP TABLE #Bicycles 
SELECT b.base_card,count(*) as pcount,max(last_updated) as last_updated 
INTO #Bicycles 
from iteminfo a  join BaseInfo b on a.base_id=b.base_id join card c on b.base_card=c.card_no where c.code_agen=1105 group by b.base_card 
select * from #Bicycles 


两个sql语句的区别,一个采用临时表,一个采用表变量。 

第一条sql语句和第二条sql语句在查询的时候执行计划居然完全不一样 
导致的结果是第一条要10s左右,而第二条就1秒就解决问题了。 

急教大家,为什么会有这么大的区别?怎么才能使两条sql语句的查询计划一致呢?

23 个解决方案

#1


@这个内存表,如果慢的话估计你计算机内存不太够吧
#这个是使用硬盘来存放临时数据,只要你tempdb所在的硬盘有控件,就没有问题

#2


@这个内存表,如果慢的话估计你计算机内存不太够吧 
#这个是使用硬盘来存放临时数据,只要你tempdb所在的硬盘有空间,就没有问题

#3


我已经调整过tempdb 的大小,和建立数据文件了!

#4


不可能吧,我的服务器是*的,,,16G的内存还不够吗?

#5


学习..

#6


INSERT INTO 和 SELECT INTO 哪个快?

#7


引用楼主 wushilin201 的帖子:
引用人家的例子! 
sql 语句一: 
declare @indextable table(base_card varchar(20),pcount int,last_updated datetime) 
insert @indextable(base_card,pcount,last_updated) 
select b.base_card,count(*) as pcount,max(last_updated) as last_updated from iteminfo a  join BaseInfo b on a.base_id=b.base_id join card c on b.base_card=c.card_no where c.code_agen=1105 group by b.base_card 
select * from @in…

执行计划既然一样,那再执行第二句话的时候,使用第一条语句的执行计划,所以很快也未必不是可能的事,
楼主再多试几次。
临时表是可以加索引的,临时表有点像临时变量,他两应该没有那么大的差别的吧!
关注中

#8


顶!

#9


引用 2 楼 moonshineidolon 的回复:
@这个内存表,如果慢的话估计你计算机内存不太够吧 
#这个是使用硬盘来存放临时数据,只要你tempdb所在的硬盘有空间,就没有问题

对,表变量是内存表。看看语句能不能优化下

#10


用临时表还没有感觉,可能是我的数据小吧。
感觉函数列最浪费性能

#11


用临时表没感觉,可能是数据量小吧。
感觉最浪费性能的是函数列

#12


引用 11 楼 shizheyangde 的回复:
用临时表没感觉,可能是数据量小吧。 
感觉最浪费性能的是函数列

#13


大家建立一个表值函数试试,,,当里面连续对@table 进行操作的时候,,,就效率好慢。。。

但SQL2000没有。。。


我现在的服务器是IBM的16核服务器

#14


是否多次执行的结果都相同?

#15


临时表当然不能和正式表相比.
你看看帮助中的介绍,建议使用表变量的多.

临时表
可以创建本地和全局临时表。本地临时表仅在当前会话中可见;全局临时表在所有会话中都可见。

本地临时表的名称前面有一个编号符 (#table_name),而全局临时表的名称前面有两个编号符 (##table_name)。

SQL 语句使用 CREATE TABLE 语句中为 table_name 指定的名称引用临时表:

CREATE TABLE #MyTempTable (cola INT PRIMARY KEY)
INSERT INTO #MyTempTable VALUES (1)

如果本地临时表由存储过程创建或由多个用户同时执行的应用程序创建,则 SQL Server 必须能够区分由不同用户创建的表。为此,SQL Server 在内部为每个本地临时表的表名追加一个数字后缀。存储在 tempdb 数据库的 sysobjects 表中的临时表,其全名由 CREATE TABLE 语句中指定的表名和系统生成的数字后缀组成。为了允许追加后缀,为本地临时表指定的表名 table_name 不能超过 116 个字符。

除非使用 DROP TABLE 语句显式除去临时表,否则临时表将在退出其作用域时由系统自动除去: 

当存储过程完成时,将自动除去在存储过程中创建的本地临时表。由创建表的存储过程执行的所有嵌套存储过程都可以引用此表。但调用创建此表的存储过程的进程无法引用此表。


所有其它本地临时表在当前会话结束时自动除去。


全局临时表在创建此表的会话结束且其它任务停止对其引用时自动除去。任务与表之间的关联只在单个 Transact-SQL 语句的生存周期内保持。换言之,当创建全局临时表的会话结束时,最后一条引用此表的 Transact-SQL 语句完成后,将自动除去此表。 
在存储过程或触发器中创建的本地临时表与在调用存储过程或触发器之前创建的同名临时表不同。如果查询引用临时表,而同时有两个同名的临时表,则不定义针对哪个表解析该查询。嵌套存储过程同样可以创建与调用它的存储过程所创建的临时表同名的临时表。嵌套存储过程中对表名的所有引用都被解释为是针对该嵌套过程所创建的表,例如:

CREATE PROCEDURE Test2
AS
CREATE TABLE #t(x INT PRIMARY KEY)
INSERT INTO #t VALUES (2)
SELECT Test2Col = x FROM #t
GO
CREATE PROCEDURE Test1
AS
CREATE TABLE #t(x INT PRIMARY KEY)
INSERT INTO #t VALUES (1)
SELECT Test1Col = x FROM #t
EXEC Test2
GO
CREATE TABLE #t(x INT PRIMARY KEY)
INSERT INTO #t VALUES (99)
GO
EXEC Test1
GO

下面是结果集:

(1 row(s) affected)

Test1Col    
----------- 
1           

(1 row(s) affected)

Test2Col    
----------- 
2           

当创建本地或全局临时表时,CREATE TABLE 语法支持除 FOREIGN KEY 约束以外的其它所有约束定义。如果在临时表中指定 FOREIGN KEY 约束,该语句将返回警告信息,指出此约束已被忽略,表仍会创建,但不具有 FOREIGN KEY 约束。在 FOREIGN KEY 约束中不能引用临时表。

考虑使用表变量而不使用临时表。当需要在临时表上显式地创建索引时,或多个存储过程或函数需要使用表值时,临时表很有用。通常,表变量提供更有效的查询处理。

#16


觉得还可以。我使用表变量处理大概10000个数据,觉得速度还可以。可能是我的要求低吧。

#17


表变量如果数据量很大,也会存在于tempDB中的。
表变量适用于小数据量的且不复杂的表。
通常使用表变量,除非数据很大切要反复操作时才用临时表的。
lz既然临时表查询都用1s想必查询数据量不小吧。

#18


特定环境出现特定的结果,不足以说明效率。

#19


引用 15 楼 dawugui 的回复:
临时表当然不能和正式表相比. 
你看看帮助中的介绍,建议使用表变量的多. 

临时表 
可以创建本地和全局临时表。本地临时表仅在当前会话中可见;全局临时表在所有会话中都可见。 

本地临时表的名称前面有一个编号符 (#table_name),而全局临时表的名称前面有两个编号符 (##table_name)。 

SQL 语句使用 CREATE TABLE 语句中为 table_name 指定的名称引用临时表: 

CREATE TABLE #MyTempTable (cola INT PRIMARY KEY)…



大师,,,有时候,,必须要使用到函数,所以必须要使用@table 临时表。。。我也知道#table的效率高好多。。。

但是,我想问,同在SQL2000,为什么执行的速度比SQL2005,SQL2008快很多,,,有时候SQL2005还超时退出

#20


引用 15 楼 dawugui 的回复:
临时表当然不能和正式表相比. 
你看看帮助中的介绍,建议使用表变量的多. 

临时表 
可以创建本地和全局临时表。本地临时表仅在当前会话中可见;全局临时表在所有会话中都可见。 

本地临时表的名称前面有一个编号符 (#table_name),而全局临时表的名称前面有两个编号符 (##table_name)。 

SQL 语句使用 CREATE TABLE 语句中为 table_name 指定的名称引用临时表: 

CREATE TABLE #MyTempTable (cola INT PRIMARY KEY)…


不是说成正比,,但效率差异太大,那也是不可能的吧!如果这样,还用函数来做什么???你自己究竟测试过没有

#21


学习~~~~ddddddddddddd

#22


到底在哪找创建的表呀~~~~

#23


引用 22 楼 lyship 的回复:
到底在哪找创建的表呀~~~~


这个问题问的好。。。

lz。。在建表的时候,加个自动主键索引。。。试试。。。

#1


@这个内存表,如果慢的话估计你计算机内存不太够吧
#这个是使用硬盘来存放临时数据,只要你tempdb所在的硬盘有控件,就没有问题

#2


@这个内存表,如果慢的话估计你计算机内存不太够吧 
#这个是使用硬盘来存放临时数据,只要你tempdb所在的硬盘有空间,就没有问题

#3


我已经调整过tempdb 的大小,和建立数据文件了!

#4


不可能吧,我的服务器是*的,,,16G的内存还不够吗?

#5


学习..

#6


INSERT INTO 和 SELECT INTO 哪个快?

#7


引用楼主 wushilin201 的帖子:
引用人家的例子! 
sql 语句一: 
declare @indextable table(base_card varchar(20),pcount int,last_updated datetime) 
insert @indextable(base_card,pcount,last_updated) 
select b.base_card,count(*) as pcount,max(last_updated) as last_updated from iteminfo a  join BaseInfo b on a.base_id=b.base_id join card c on b.base_card=c.card_no where c.code_agen=1105 group by b.base_card 
select * from @in…

执行计划既然一样,那再执行第二句话的时候,使用第一条语句的执行计划,所以很快也未必不是可能的事,
楼主再多试几次。
临时表是可以加索引的,临时表有点像临时变量,他两应该没有那么大的差别的吧!
关注中

#8


顶!

#9


引用 2 楼 moonshineidolon 的回复:
@这个内存表,如果慢的话估计你计算机内存不太够吧 
#这个是使用硬盘来存放临时数据,只要你tempdb所在的硬盘有空间,就没有问题

对,表变量是内存表。看看语句能不能优化下

#10


用临时表还没有感觉,可能是我的数据小吧。
感觉函数列最浪费性能

#11


用临时表没感觉,可能是数据量小吧。
感觉最浪费性能的是函数列

#12


引用 11 楼 shizheyangde 的回复:
用临时表没感觉,可能是数据量小吧。 
感觉最浪费性能的是函数列

#13


大家建立一个表值函数试试,,,当里面连续对@table 进行操作的时候,,,就效率好慢。。。

但SQL2000没有。。。


我现在的服务器是IBM的16核服务器

#14


是否多次执行的结果都相同?

#15


临时表当然不能和正式表相比.
你看看帮助中的介绍,建议使用表变量的多.

临时表
可以创建本地和全局临时表。本地临时表仅在当前会话中可见;全局临时表在所有会话中都可见。

本地临时表的名称前面有一个编号符 (#table_name),而全局临时表的名称前面有两个编号符 (##table_name)。

SQL 语句使用 CREATE TABLE 语句中为 table_name 指定的名称引用临时表:

CREATE TABLE #MyTempTable (cola INT PRIMARY KEY)
INSERT INTO #MyTempTable VALUES (1)

如果本地临时表由存储过程创建或由多个用户同时执行的应用程序创建,则 SQL Server 必须能够区分由不同用户创建的表。为此,SQL Server 在内部为每个本地临时表的表名追加一个数字后缀。存储在 tempdb 数据库的 sysobjects 表中的临时表,其全名由 CREATE TABLE 语句中指定的表名和系统生成的数字后缀组成。为了允许追加后缀,为本地临时表指定的表名 table_name 不能超过 116 个字符。

除非使用 DROP TABLE 语句显式除去临时表,否则临时表将在退出其作用域时由系统自动除去: 

当存储过程完成时,将自动除去在存储过程中创建的本地临时表。由创建表的存储过程执行的所有嵌套存储过程都可以引用此表。但调用创建此表的存储过程的进程无法引用此表。


所有其它本地临时表在当前会话结束时自动除去。


全局临时表在创建此表的会话结束且其它任务停止对其引用时自动除去。任务与表之间的关联只在单个 Transact-SQL 语句的生存周期内保持。换言之,当创建全局临时表的会话结束时,最后一条引用此表的 Transact-SQL 语句完成后,将自动除去此表。 
在存储过程或触发器中创建的本地临时表与在调用存储过程或触发器之前创建的同名临时表不同。如果查询引用临时表,而同时有两个同名的临时表,则不定义针对哪个表解析该查询。嵌套存储过程同样可以创建与调用它的存储过程所创建的临时表同名的临时表。嵌套存储过程中对表名的所有引用都被解释为是针对该嵌套过程所创建的表,例如:

CREATE PROCEDURE Test2
AS
CREATE TABLE #t(x INT PRIMARY KEY)
INSERT INTO #t VALUES (2)
SELECT Test2Col = x FROM #t
GO
CREATE PROCEDURE Test1
AS
CREATE TABLE #t(x INT PRIMARY KEY)
INSERT INTO #t VALUES (1)
SELECT Test1Col = x FROM #t
EXEC Test2
GO
CREATE TABLE #t(x INT PRIMARY KEY)
INSERT INTO #t VALUES (99)
GO
EXEC Test1
GO

下面是结果集:

(1 row(s) affected)

Test1Col    
----------- 
1           

(1 row(s) affected)

Test2Col    
----------- 
2           

当创建本地或全局临时表时,CREATE TABLE 语法支持除 FOREIGN KEY 约束以外的其它所有约束定义。如果在临时表中指定 FOREIGN KEY 约束,该语句将返回警告信息,指出此约束已被忽略,表仍会创建,但不具有 FOREIGN KEY 约束。在 FOREIGN KEY 约束中不能引用临时表。

考虑使用表变量而不使用临时表。当需要在临时表上显式地创建索引时,或多个存储过程或函数需要使用表值时,临时表很有用。通常,表变量提供更有效的查询处理。

#16


觉得还可以。我使用表变量处理大概10000个数据,觉得速度还可以。可能是我的要求低吧。

#17


表变量如果数据量很大,也会存在于tempDB中的。
表变量适用于小数据量的且不复杂的表。
通常使用表变量,除非数据很大切要反复操作时才用临时表的。
lz既然临时表查询都用1s想必查询数据量不小吧。

#18


特定环境出现特定的结果,不足以说明效率。

#19


引用 15 楼 dawugui 的回复:
临时表当然不能和正式表相比. 
你看看帮助中的介绍,建议使用表变量的多. 

临时表 
可以创建本地和全局临时表。本地临时表仅在当前会话中可见;全局临时表在所有会话中都可见。 

本地临时表的名称前面有一个编号符 (#table_name),而全局临时表的名称前面有两个编号符 (##table_name)。 

SQL 语句使用 CREATE TABLE 语句中为 table_name 指定的名称引用临时表: 

CREATE TABLE #MyTempTable (cola INT PRIMARY KEY)…



大师,,,有时候,,必须要使用到函数,所以必须要使用@table 临时表。。。我也知道#table的效率高好多。。。

但是,我想问,同在SQL2000,为什么执行的速度比SQL2005,SQL2008快很多,,,有时候SQL2005还超时退出

#20


引用 15 楼 dawugui 的回复:
临时表当然不能和正式表相比. 
你看看帮助中的介绍,建议使用表变量的多. 

临时表 
可以创建本地和全局临时表。本地临时表仅在当前会话中可见;全局临时表在所有会话中都可见。 

本地临时表的名称前面有一个编号符 (#table_name),而全局临时表的名称前面有两个编号符 (##table_name)。 

SQL 语句使用 CREATE TABLE 语句中为 table_name 指定的名称引用临时表: 

CREATE TABLE #MyTempTable (cola INT PRIMARY KEY)…


不是说成正比,,但效率差异太大,那也是不可能的吧!如果这样,还用函数来做什么???你自己究竟测试过没有

#21


学习~~~~ddddddddddddd

#22


到底在哪找创建的表呀~~~~

#23


引用 22 楼 lyship 的回复:
到底在哪找创建的表呀~~~~


这个问题问的好。。。

lz。。在建表的时候,加个自动主键索引。。。试试。。。