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. spark in eclipse---Spark学习笔记3

    想要调试源码,还是要放到eclipse里面去.先生成eclipse项目,下载依赖包 victor@victor-ubuntu:~/software/incubator-spark-0.8.1-incu ...

  2. jQuery实现发送验证码倒计时60秒

    前端HMTL: <div class="form_box"> <div class="line mb40"> <div class ...

  3. PhpStorm 超强语言模板的支持

    原文:[转]PhpStorm 超强语言模板的支持 最近遇到一些PhpStorm编程的问题: 在使用Zen Coding插件时,PHPStorm不像Notepad++那样随便使用.PHPStorm只有在 ...

  4. 蓝色的成长记录——追逐DBA(8):为了夺回SP报告,回顾oracle的STATSPACK实验

    ***********************************************声明*************************************************** ...

  5. ASP.NET MVC创建的网站

    ASP.NET MVC创建的网站   最近在写一个网站,昨天刚写完,由于要和朋友一起测试,但是他电脑上没有环境,所以希望我在自己电脑上部署一下,让他直接通过浏览器来访问来测试,所以从昨晚到今天上午,通 ...

  6. C语言生成2000w行数据

    最近一直抽空学习shell,脚本语言看多了多多少少有些蛋疼不适,所以捡起以前遇到的一个C语言的问题看看. 原先应该是在C++吧关注的一个帖子,楼主为了测试数据库性能需要如下形式的数据要求: 字符串长度 ...

  7. Objective-C和Swift

    在项目中同时使用Objective-C和Swift 苹果发布的Swift语言可以和之前的Objective-C语言同时存在于一个项目中. 可能有人会认为是同一个类文件中既可以有Objective-C也 ...

  8. SpringMVC类型转换、数据绑定

    SpringMVC类型转换.数据绑定详解[附带源码分析] 目录 前言 属性编辑器介绍 重要接口和类介绍 部分类和接口测试 源码分析 编写自定义的属性编辑器 总结 参考资料 前言 SpringMVC是目 ...

  9. Manager(管理器)

    Manager(管理器) 索引 意图 结构 参与者 适用性 效果 实现 实现方式(一):Manager 模式的示例实现. 意图 将对一个类的所有对象的管理封装到一个单独的管理器类中. 这使得管理职责的 ...

  10. 【WCF系列一】WCF入门教程(图文) VS2012

    WCF的全称是Windows Communication Foundation,从英文名称上看,WCF就是基于Windows下一种通讯的基础架构.利用WCF能够实现基于Windows下的各种通讯技术的 ...