接上文"CTE,临时表,表变量区别跟具体适用场景分析",我们再看一个问题:
----------------------------------------------------------------------------------------
问题
----------------------------------------------------------------------------------------
例子1:
create procedure Proc1
as
begin
create table #t1(a int, b int);
insert into #t1 values(1,2);
select * from #t1;
end
exec Proc1
go
exec Proc1
GO
例子2
create procedure Proc1
as
begin
create table #t1(a int, b int);
insert into #t1 values(1,2);
exec Proc2;
end
go
create procedure Proc2
as
begin
select * from #t1;
end
go
exec Proc1
go
exec Proc1
go
我们可以看到,上面的2个例子,SP1跟SP2,
在SP1中第二次执行exec Proc1的时候,不会引起重编译,
但是在SP2中第二次执行exec Proc1的时候,却会引起重编译,为什么呢?
----------------------------------------------------------------------------------------
答案
----------------------------------------------------------------------------------------
1.第一个case,我很久以前经常用表变量去inner join其它的表,当发现表变量数据稍多,整个语句就会变的很差,之后就一直按“数据很少就用表变量,数据多点就用临时表。”刚看到这个贴子,就想了想查了查,主要原因还是表变量的行数未知,SQL优化器必须估一个值,这个值往往是很小,在这种情况下去inner join其它表,基本上都会是Nested loop join,此时一旦表变量数据量大,性能将会变得极差。而这种情况下我们往往需要merge join 或 hash join才更有效率,recompile选项能让优化器去更新表变量的统计信息,而这样就能根据统计信息生成合理的执行计划。
2.至于第二个关于存储过程的case,两个场景主要关键点还是第二个proc2中引用非自己创建的临时表,这个引用是依靠临时表ID,当执行proc1生成临时表时,名字(执行计划依靠名字)不变但id会变,而proc2依靠这个id,这相当于proc2要查的临时表架构发生变化,所以每次都要重编译,如果在proc1里同时有两个exec proc2,那么第二个不会重编译,因为此时它可以重新第一个exec proc2的执行计划了,因为两个exec proc2引用的临时表是同名同ID。Hr,gsS颯銐砆顣槝0s