CTE和临时表性能比较CTE最优秀的地方是在实现递归操作,和替代绝大部分游标的功能,但是对于大数据量,由于cte不能建索引,所以明显比临时表差。
例如:当需要查询大数据时,临时表的性能远比CTE要高,以下两个查询结果相同,但是CTE 性能明显不如临时表CTE查询,耗时60Sif OBJECT_ID('tempdb.dbo.#POUnsign')is not nulldrop table#POUnsign;;with cte_POUnsignWF as(select distinct a.Applicationid collate SQL_Latin1_General_CP1_CI_AS as Applicationid --必须使用AS 重命名字段,否则cte查询的结果中没有列名,a.Applicant collate SQL_Latin1_General_CP1_CI_AS as Applicant,f.Approver collate SQL_Latin1_General_CP1_CI_AS as Approver,erManager collate SQL_Latin1_General_CP1_CI_AS as UserManager,f.FlowDescription collate SQL_Latin1_General_CP1_CI_AS as FlowDescriptionfrom[OAWF2].[QSMCWF].[dbo].[WFApprove]a with(nolock)inner join[OAWF2].[QSMCWF].[dbo].[WFFlow]f with(nolock)on a.ApplicationID=f.ApplicationID and a.FormID=f.FormID anda.CurrentFlowNo=f.FlowNoinner join dbo.tscUser u with(nolock)on a.Applicant=erName collate SQL_Latin1_General_CP1_CI_ASwhere a.FormID='WF0032'and f.ApproveStatus='4'and a.ApplyStatus='0'andf.SequenceNo=1)select distinct pu.Applicant,pu.Approver,erManager,pu.FlowDescriptioninto#POUnsignfrom cte_POUnsignWF puinner join dbo.tdsPoSignInfo ps with(nolock)on pu.Applicationid=ps.ApplicationID collate SQL_Latin1_General_CP1_CI_ASinner join dbo.tdsPoHeader ph with(nolock)on ph.Ebeln=ps.Ebeln collateSQL_Latin1_General_CP1_CI_ASleft join dbo.tdsAupo a with(nolock)on a.EBELN=ps.Ebeln collateSQL_Latin1_General_CP1_CI_AS and a.EBELP='00010'collate SQL_Latin1_General_CP1_CI_AS where ph.Sexkz in('0','1')and a.DECLITEM is nullselect*from#POUnsigndrop table#POUnsign临时表查询:耗时8sif OBJECT_ID('tempdb.dbo.#POUnsign')is not nulldrop table#POUnsign;if OBJECT_ID('tempdb.dbo.#POUnsignWF')is not nulldrop table#POUnsignWF;select distinct a.Applicationid collate SQL_Latin1_General_CP1_CI_AS as Applicationid--必须使用AS 重命名字段,否则查询的结果中没有列名,不能创建临时表,a.Applicant collate SQL_Latin1_General_CP1_CI_AS as Applicant,f.Approver collate SQL_Latin1_General_CP1_CI_AS as Approver,erManager collate SQL_Latin1_General_CP1_CI_AS as UserManager,f.FlowDescription collate SQL_Latin1_General_CP1_CI_AS asFlowDescriptioninto#POUnsignWFfrom[OAWF2].[QSMCWF].[dbo].[WFApprove]a with(nolock)inner join[OAWF2].[QSMCWF].[dbo].[WFFlow]f with(nolock)on a.ApplicationID=f.ApplicationID and a.FormID=f.FormID and a.CurrentFlowNo=f.FlowNo inner join dbo.tscUser u with(nolock)on a.Applicant=erName collate SQL_Latin1_General_CP1_CI_ASwhere a.FormID='WF0032'and f.ApproveStatus='4'and a.ApplyStatus='0'and f.SequenceNo=1select distinct pu.Applicant,pu.Approver,erManager,pu.FlowDescriptioninto#POUnsignfrom#POUnsignWF puinner join dbo.tdsPoSignInfo ps with(nolock)on pu.Applicationid=ps.ApplicationID collate SQL_Latin1_General_CP1_CI_ASinner join dbo.tdsPoHeader ph with(nolock)on ph.Ebeln=ps.Ebeln collateSQL_Latin1_General_CP1_CI_ASleft join dbo.tdsAupo a with(nolock)on a.EBELN=ps.Ebeln collateSQL_Latin1_General_CP1_CI_AS and a.EBELP='00010'collate SQL_Latin1_General_CP1_CI_AS where ph.Sexkz in('0','1')and a.DECLITEM is nullselect*from#POUnsigndrop table#POUnsigndrop table#POUnsignWF以下是从网上引用的一篇文章,说的很言简意赅,也解释了我的疑问。
临时表、表变量、CTE的比较1、临时表临时表包括:以#开头的局部临时表,以##开头的全局临时表。
a、存储不管是局部临时表,还是全局临时表,都会放存放在tempdb数据库中。
b、作用域局部临时表:对当前连接有效,只在创建它的存储过度、批处理、动态语句中有效,类似于C语言中局部变量的作用域。
全局临时表:在所有连接对它都结束引用时,会被删除,对创建者来说,断开连接就是结束引用;对非创建者,不再引用就是结束引用。
但最好在用完后,就通过drop table 语句删除,及时释放资源。
c、特性与普通的表一样,能定义约束,能创建索引,最关键的是有数据分布的统计信息,这样有利于优化器做出正确的执行计划,但同时它的开销和普通的表一样,一般适合数据量较大的情况。
有一个非常方便的select ... into 的用法,这也是一个特点。
2、表变量a、存储表变量存放在tempdb数据库中。
b、作用域和普通的变量一样,在定义表变量的存储过程、批处理、动态语句、函数结束时,会自动清除。
c、特性可以有主键,但不能直接创建索引,也没有任何数据的统计信息。
SQL Server是以表变量的数据在上千条前提,来生成执行计划的,所以表变量适合数据量相对较小的情况。
必须要注意的是,表变量不受事务的约束,下面的例子说明了这一点:declare@tb table(v int primary key,vv varchar(10))begin traninsert into@tbselect 1,'aa'rollback tran--虽然上面回滚了事务,但还是会返回1条记录select*from@tbbegin tranupdate@tbset vv='bb'where v= 1rollback tran--返回的数据显示,update操作成功,根本没有回滚select*from@tb3、CTECTE,就是通用表表达式。
a、存储产生的数据一般存储在内存,不会持久化存储。
也可以持久化:;with cteas(select 1 as v,'aa'as vvunion allselect 2,'bb')--把cte的数据存储在tb_cte表select*into tb_ctefrom cteselect*from tb_cte;--运用cte,删除数据;with cte_deleteas(select*from tb_cte)delete from cte_delete where V= 1--返回1条数据,另一条已删除select*from tb_cte当然,在实际运行时,有些部分,比如假脱机,会把数据存储在tempdb的worktable、workfile中,另外,一些大的hash join和排序操作,也会把中间数据存储在tempdba。
b、作用域只存在于当前的语句。
c、特性在同一个语句中,一次定义,可以多次引用。
另外,可以定义递归语句,不过这个递归语句的性能,还不如写个while循环来的好。