此次看一下臨時表,表變量和Union命令方面是否能夠被優化呢?html
閱讀導航數據庫
1、臨時表和表變量express
1、臨時表和表變量架構
不少數據庫開發者使用臨時表和表變量將代碼分解成小塊代碼來簡化複雜的邏輯。可是使用這個的後果就是可能帶來性能的損害性能
1. 對I/O子系統的影響 (存儲區域網絡SAN 或邏輯存儲),這是因爲增長了頁和頁I/O閂鎖等待,這樣等待被認爲是最差的等待,這也可能會增長臨時數據庫的密集競爭進而致使高分配請求,最後可能出現全局分配映射頁(GAM)、共享全局映射頁(SGAM)或可用空間(PFS)癱瘓。優化
2. 影響CPU利用率,這是因爲Cxpacket在索引不足的臨時數據庫上等待結果,若是臨時表有彙集索引和非彙集索引,這樣的現象能夠被減緩。spa
所以,最好有限的使用臨時表。code
在必須使用臨時表的狀況下,能夠參照一下預防措施:orm
那麼,採用什麼辦法避免使用臨時表和表變量呢?
例子 :
首先,在新數據庫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
2、本次的另外一個重頭戲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
期待下一篇吧!