T-SQL 临时表、表变量、UNION

这次看一下临时表,表变量和Union命令方面是否可以被优化呢?

阅读导航

一、临时表和表变量

二、本次的另一个重头戏UNION 命令

一、临时表和表变量

很多数据库开发者使用临时表和表变量将代码分解成小块代码来简化复杂的逻辑。但是使用这个的后果就是可能带来性能的损害

1. I/O子系统的影响 (存储区域网络SAN 或逻辑存储),这是由于增加了页和页I/O闩锁等待,这样等待被认为是最差的等待,这也可能会增加临时数据库的密集竞争进而导致高分配请求,最后可能出现全局分配映射页(GAM)、共享全局映射页(SGAM)或可用空间(PFS)瘫痪。

  • 全局分配映射页(Global Allocation Map, GAM)用于跟踪区的使用情况,每个GAM页可以跟踪64000个区或者说4GB的数据。在GAM页中,如果某个位值为0,则表示它所对应的区已经分配给了某个对象使用,值为1时表示这个区是空闲的。
  • 共享全局分配映射页(Shared Global Allocation Map, SGAM)功能和GAM是一样的,所不同的就是SGAM是用来管理混合区的。不过它的位图映射关系正好是相反的:在GAM中设置为1的,在SGAM中设置为0——用于代表一个空闲的区。
  • 页可用空间(Page Free Space, PFS),这种页记录了某个页是否分配给了某个对象,并且记录这个页上有多少可用的空间,位图映射值可显示一个页的使用率是50%、85%、95%或是95%以上。SQL Server根据这个信息来决定是否要给一行数据分配新的空间

2. 影响CPU利用率,这是由于Cxpacket在索引不足的临时数据库上等待结果,如果临时表有聚集索引和非聚集索引,这样的现象可以被减缓。

因此,最好有限的使用临时表。

在必须使用临时表的情况下,可以参照一下预防措施:

  • 使用临时表(create table #Temp)而不是使用表变量(Declare @table table),这样做的原因是可以在临时表上使用索引。
  • 使用临时表时,用小型数据量的小表来限制性能影响。
  • 如果临时表中使用inner join , group by , order by 或 where,要确保临时表有聚集索引或非聚集索引。

那么,采用什么办法避免使用临时表和表变量呢?

  1. CTE表达式(Common Table Expression, CTE
  2. 子查询
  3. 在数据库架构中创建物理表,而不是在历史数据库中创建临时表。
  4. SQL Server 2008以后,表参数是可以用的。

例子 :

首先,在新数据库MyDemo中创建新表

   1:  --创建新表
   2:  use MyDemo 
   3:  CREATE TABLE [dbo].[Employees]( 
   4:        [empid] [int] IDENTITY(1,1) NOT NULL, 
   5:        [empname] [nvarchar](100) NULL, 
   6:        [deptid] [int] NULL, 
   7:        [Salary] [float] NULL, 
   8:  CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED 
   9:  ( [empid] ASC ) 
  10:  WITH 
  11:  (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, 
  12:  ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY] 
  13:  ) ON [PRIMARY] 
  14:  GO 
  15:  CREATE TABLE [dbo].[Departments]( 
  16:        [deptid] [int] IDENTITY(1,1) NOT NULL, 
  17:        [deptname] [nchar](10) NULL, 
  18:  CONSTRAINT [PK_Departments] PRIMARY KEY CLUSTERED 
  19:  (  [deptid] ASC   ) 
  20:  WITH 
  21:  (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
  22:  IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY] ) 
  23:  ON [PRIMARY] 
  24:  GO 

使用表变量:

   1:  alter procedure Performance_Issue_Table_Variables 
   2:  as 
   3:  begin 
   4:  SET NOCOUNT ON; 
   5:  declare @table table(empid int, empname varchar (25),Department varchar (25) ,Salary int) 
   6:  insert into @table select S.empid,S.empname,T.deptname,S.salary from Employees s inner join Departments T ON S.deptid =T.deptid 
   7:  SELECT COUNT (empid) ,Department,Salary  FROM @table GROUP BY Department,Salary HAVING Salary>2000 
   8:  end 
 

使用临时表:

   1:  Create procedure Performance_Issue_Table_Variables 
   2:  as 
   3:  begin 
   4:  SET NOCOUNT ON; 
   5:  create table #table (empid int, empname varchar (25),Department varchar (25) ,Salary int) 
   6:  create clustered index #table_index1 on #table (empid asc ) 
   7:  create nonclustered index #table_index2 on #table (Salary) include (Department,empid ) 
   8:  insert into #table select S.empid,S.empname,T.deptname,S.salary from Employees s 
   9:  inner join Departments T ON S.deptid =T.deptid 
  10:  SELECT COUNT (empid) ,Department,Salary  FROM #table GROUP BY Department,Salary HAVING Salary>2000 
  11:  DROP TABLE #table 
  12:  end

使用CTE表达式:

   1:  Create procedure Performance_Solution_CTEexpression 
   2:  as 
   3:  begin 
   4:  SET NOCOUNT ON; 
   5:  With temp as 
   6:  ( 
   7:  select S.empid,S.empname,T.deptname as Department,S.salary from Employees s inner 
   8:  join Departments T ON S.deptid =T.deptid 
   9:  ) 
  10:  SELECT COUNT (empid) ,Department,Salary  FROM temp GROUP BY Department,Salary HAVING Salary>2000 
  11:  end

使用表参数 
表参数可通过三个步骤实现 
第一,创建一个新的数据表:

   1:  create type Specialtable as table 
   2:  (EmployeeID int NULL, 
   3:  EmployeeName Nvarchar (50) Null ) 

接下来,创建存储过程,并接受这个表所谓参数输入:

   1:  create  procedure Performance_Solution_Table_Paramters @Temptable Specialtable Readonly 
   2:  as 
   3:  begin 
   4:  select * from @Temptable 
   5:  end 
   6:  Finally, execute the stored procedure : 
   7:  declare @temptable_value specialtable 
   8:  insert into @temptable_value select '1','Jone' union select '2', 'Bill' 
   9:  exec dbo.SP_Results @temptable=@temptable_value 

使用子查询

   1:  Create procedure Performance_Solution_SubQuery 
   2:  as 
   3:  begin 
   4:  SET NOCOUNT ON; 
   5:  SELECT COUNT (empid) ,S.Department,Salary  FROM 
   6:  (select S.empid,S.empname,T.deptname as Department,S.salary from Employees s inner join Departments T ON S.deptid =T.deptid) S 
   7:  GROUP BY Department,Salary HAVING Salary>2000 
   8:  end

使用物理表

   1:  create table schema_table (empid int, empname varchar (25),Department varchar (25) ,Salary int) 
   2:  create clustered index schema_table_index1 on schema_table (empid asc ) 
   3:  create nonclustered index schema_table_index2 on schema_table (Salary) include (Department,empid ) 
   4:  insert into schema_table select S.empid,S.empname,T.deptname,S.salary from Employees s inner join Departments T ON S.deptid =T.deptid 
   5:  go 
   6:  Create procedure Performance_Solution_PhysicalTables 
   7:  as 
   8:  begin 
   9:  SET NOCOUNT ON; 
  10:  SELECT COUNT (empid) ,Department,Salary  FROM schema_table GROUP BY Department,Salary HAVING Salary>2000 
  11:  end

二、本次的另一个重头戏UNION 命令

使用Union命令,和使用临时表一样,会影响I/O子系统(如,页和页I/O闩锁等待)。但是很多数据库开发者仍然使用Union命令处理复杂的业务逻辑。

选择/改善Union :

· 使用Case When 子句代替,它们可以做聚合和详细的查询

· 使用动态查询:用强大的sp_executesq来节省每次运行查询执行计划,节省时间消耗。存储过程中使用If Else 语句决定查询语句适合的一组参数,这样可以根据传入存储过程的参数控制Union的数量。

· 选择排序语句内使用Union,使用轻量级的选择查询减少重量级的选择查询消耗的页闩锁等待。

例子:

使用性能较差的Union命令:

   1:  create procedure Poor_Performing_UnionSP 
   2:  as 
   3:  begin 
   4:  SET NOCOUNT ON; 
   5:  select S.empid,S.empname,T.deptname,S.salary from Employees s inner join Departments T ON S.deptid =T.deptid WHERE T.deptid>1 and S.salary>5000 
   6:  UNION 
   7:  select S.empid,S.empname,'Management deparments' as deptname,S.salary from Employees s inner join Departments T ON S.deptid =T.deptid WHERE T.deptid=1 and S.salary  >10000 
   8:  end

使用Case When语句: 

   1:  create procedure PerformantSP_Grid_Results_Using_CaseWhen 
   2:  AS 
   3:  BEGIN 
   4:  select S.empid,S.empname, 
   5:  case when T.deptid>1 and S.salary>5000  then T.deptname 
   6:  when T.deptid=1 and S.salary>10000 then 'Management deparments'  end as deptname 
   7:  ,S.salary 
   8:  from Employees s inner join Departments T ON S.deptid =T.deptid 
   9:  END 
  10:  GO

使用Union获得聚合结果:

   1:  create procedure Poor_Performing_Union_Aggregate_Results 
   2:  as 
   3:  begin 
   4:  SET NOCOUNT ON; 
   5:  select count (S.empid)as Employee_count,T.deptname,S.salary from Employees s 
   6:  inner join Departments T 
   7:  ON S.deptid =T.deptid WHERE T.deptid>1 and S.salary>10000  group by T.deptname,S.salary 
   8:  end

使用Case When获得集合结果:

   1:  create procedure PerformantSP_Aggregate_Results_Using_CaseWhen 
   2:  as 
   3:  begin 
   4:  SET NOCOUNT ON; 
   5:  select sum (case when   T.deptid>1 and S.salary>10000  then 1 else 0 end) 
   6:  as Employee_count2 
   7:  ,T.deptname,S.salary 
   8:  from Employees s inner join Departments T ON S.deptid =T.deptid 
   9:  group by T.deptname,S.salary 
  10:  end

期待下一篇吧!

在此谢谢读完这篇博客,有什么写的不对的地方请指正

有帮助就推荐下,有感想就写下留言,不满意也留言,有问题就更正。

 
 
分类: SQL
标签: 数据库

T-SQL 临时表、表变量、UNION的更多相关文章

  1. SQL Server 表变量和临时表的区别

    SQL Server 表变量和临时表的区别 一.表变量 表变量在SQL Server 2000中首次被引入.表变量的具体定义包括列定义,列名,数据类型和约束.而在表变量中可以使用的约束包括主键约束,唯 ...

  2. sql server 表变量、表类型、临时表

    sql server 中临时表分为会话临时表和永久临时表.会话临时表在会话结束后自动被删除,永久临时表与基本表的使用上基本无差异,需要显示调用drop将其删除. 创建临时表 创建会话临时表 creat ...

  3. [转]SQL Server 表变量和临时表的区别

    一.表变量 表变量在SQL Server 2000中首次被引入.表变量的具体定义包括列定义,列名,数据类型和约束.而在表变量中可以使用的约束包括主键约束,唯一约束,NULL约束和CHECK约束(外键约 ...

  4. SQL SERVER表变量和临时表

    一.表变量 表变量在SQL Server 2000中首次被引入.表变量的具体定义包括列定义,列名,数据类型和约束.而在表变量中可以使用的约束包括主键约束,唯一约束,NULL约束和CHECK约束(外键约 ...

  5. sql临时表与变量表

    1)临时表存储在 tempdb 中,当不再使用时会自动删除 一般使用如下: --创建临时表 select * into #temp from TABLE --使用临时表 select * from # ...

  6. sql server 表变量存储临时查询数据

    对于使用sql server 编写存储过程或者类似的sql 查询的时候我们使用表变量进行临时数据的存储,可以方便我们进行下来的数据处理 表变量的使用类似如下: declare @userinfo ta ...

  7. sql创建表变量,转百分数

    declare @tab table( ID nt identity(1,1) primary key, --从1开始,每次自增1 ,Name nvarchar(200) ) declare a fl ...

  8. SQL 表变量和临时表

    SQL 表变量和临时表 表变量:存储在内存中,作用域是脚本的执行过程中,脚本执行完毕之后就会释放内存,适合短时间内存储数据量小的数据集. 优点:使用灵活,使用完之后立即释放,不占用物理存储空间 缺点: ...

  9. SQL Server中的临时表和表变量 Declare @Tablename Table

    在SQL Server的性能调优中,有一个不可比面的问题:那就是如何在一段需要长时间的代码或被频繁调用的代码中处理临时数据集?表变量和临时表是两种选择.记得在给一家国内首屈一指的海运公司作SQL Se ...

  10. SQL Server中的临时表和表变量

    SQL Server中的临时表和表变量 作者:DrillChina出处:blog2008-07-08 10:05 在SQL Server的性能调优中,有一个不可比拟的问题:那就是如何在一段需要长时间的 ...

随机推荐

  1. iOS 开发者必不可少的 75 个工具

    如果你去到一位熟练的木匠的工作室,你总是能发现他/她有一堆工具来完成不同的任务. 软件开发同样如此.你可以从软件开发者如何使用工具中看出他水准如何.有经验的开发者精于使用工具.对你目前所使用的工具不断 ...

  2. Python - 字符串的替换(interpolation) 具体解释

    字符串的插值(interpolation) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/27054263 字符串的替换 ...

  3. leetcode先刷_Unique Binary Search Trees II

    可能没想到,人的简单方法,关于质询的问题提出做. 如何把产生出来的所有的树木?所使用的方法当然是递归,但是有一个致命的问题,假设根节点,然后做一个递归,所以这是非常多的公共树木的根,结果肯定是一团糟. ...

  4. 安卓MonkeyRunner源码分析之工作原理架构图及系列集合

    花了点时间整理了下MonkeyRunner的工作原理图,请配合本人博客里面MonkeyRunner其他源码分析文章进行阅读.下面整理成相应系列列表方便大家阅读: MonkeyRunner源码分析之-谁 ...

  5. DDD分层架构之值对象(层超类型篇)

    DDD分层架构之值对象(层超类型篇) 上一篇介绍了值对象的基本概念,得到了一些朋友的支持,另外也有一些朋友提出了不同意见.这其实是很自然的事情,设计本来就充满了各种可能性,没有绝对正确的做法,只有更好 ...

  6. 四种方案:将OpenStack私有云部署到Hadoop MapReduce环境中

    摘要:OpenStack与Hadoop被誉为继Linux之后最有可能获得巨大成功的开源项目.这二者如何结合成为更猛的新方案?业内给出两种答案:Hadoop跑在OpenStack上或OpenStack部 ...

  7. mysql通过字段注释查找字段名称

    原文:mysql通过字段注释查找字段名称 有时候表的字段太多,只是大致记得表的注释,想通过字段注释查找字段名称,可以用如下语句: SELECT COLUMN_NAME,column_comment F ...

  8. android 布局属性大全---初学者必备

    Android功能强大,界面华丽,但是众多的布局属性就害苦了开发者,下面这篇文章结合了网上不少资料,花费本人一个下午搞出来的,希望对其他人有用. 第一类:属性值为true或false android: ...

  9. JQuery的两个each方法的注意点

    Jquery官网上两个each用法: http://api.jquery.com/jQuery.each/ http://api.jquery.com/each/ 使用时注意点 <!DOCTYP ...

  10. 使用UpdatePanel控件

    使用UpdatePanel控件(二) UpdatePanel可以用来创建丰富的局部更新Web应用程序,它是ASP.NET 2.0 AJAX Extensions中很重要的一个控件,其强大之处在于不用编 ...