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. nolock引发

      Sql Server之旅——终点站 nolock引发的三级事件的一些思考   曾今有件事情让我记忆犹新,那年刚来携程不久,马上就被安排写一个接口,供企鹅公司调用他们员工的差旅信息,然后我就三下五除 ...

  2. MVC 5 Web编程2 -- URL映射

    ASP.NET MVC 5 Web编程2 -- URL映射(路由原理) 2015-02-12 08:50 by hangwei, 704 阅读, 5 评论, 收藏, 编辑 本章将讲述ASP.NET M ...

  3. 安卓MonkeyRunner源码分析之与Android设备通讯方式

    如前文<谁动了我的截图?--Monkeyrunner takeSnapshot方法源码跟踪分析>所述,本文主要会尝试描述android的自动化测试框架MonkeyRunner究竟是如何和目 ...

  4. 配置phonegap Android开发环境

    phonegap的安装路途曲折,首先要基于多种程序,中途还要解决各种问题,下面是phonegap需要的程序 1.NodeJs 2.Phonegap 3.jdk,jre 4.Apache Ant 5.A ...

  5. APUE学习笔记(2):lseek()练习与文件洞

    对于lseek函数早在大一的C语言课上就有接触,但是几乎没有使用过,只记得是和文件偏移操作相关的 看了APUE上的示例,又使用od工具查看了内容,果然很神奇,很新鲜 figure3.2.c [c] # ...

  6. 图文解说PhpStorm 7.0版本新增内置工具

    很多PHP开发者,都比较关心PhpStorm 7.0版本的内置工具.今天我们将测试内置的Vagrant工具和SSH远端控制台工具. Vagrant工具集成在PhpStorm 7.0版本中,提高了IDE ...

  7. Unity3D开发必备神器(Visual Studio Tools for Unity)

    Unity3D开发必备神器(Visual Studio Tools for Unity) 开发Unity3D程序你用的什么IDE呢? 1.MonoDevelop 2.VS 可能你的回答是这样的,我用的 ...

  8. Windows 下安装 Oracle 12c 教程

    原文 Windows 下安装 Oracle 12c 教程 申明:本文原作者:Jmq   本文给大家带来的是 Oracle 12C 的安装教程. 1.准备 1.1 下载 Oracle 12c 安装程序 ...

  9. delphi字符串函数大全

    转帖:delphi字符串函数大全 2009-11-17 16:43:55 分类: delphi字符串函数大全 ━━━━━━━━━━━━━━━━━━━━━首部 function StringToGUID ...

  10. EF的四种开发模式

    EF提供了四种开发模式,具体如下:(转载)Code First(New DataBase) :在代码中定义类和映射关系并通过model生成数据库,使用迁移技术更新数据库.Code First(Exis ...