1. 程式人生 > 程式設計 >T-sql指令碼級別優化

T-sql指令碼級別優化

一概述

sql語句的執行時間一般會主要花在3步:語句編譯,語句執行,結果集返回.

結果集返回的速度一般和sql server 自身沒有太大關係,所以一般不會在語句調優的時候考慮。 所以語句調優時,focus在於編譯和語句執行各花了多少時間,哪一段時間有優化空間,以及怎麼優化


二常見優化套路

1 表關聯的時候 最好縮小範圍之後再關聯,這樣耗費記憶體少。
2 條件都出在一張表,為什麼不把刷選都做掉,再join呢?——這樣join的資料集小,
3 搜尋條件多的,可以考慮使用動態sql——考慮根據是否傳參,拼接where條件以及join表——case when
4 order by 排序,表關聯on——考慮索引
5 儘量不用檢視,啟用物理表,表關聯的時候 最好縮小範圍之後再關聯,這樣耗費記憶體少。
6 單表——索引
7 多表——join 順序,關聯條件加索引,儘量不要join檢視複製程式碼

三 優化指北

1 索引   待續:《索引的本質》 《資料庫內部儲存》

業務系統大多數時間基本上是排序和查詢。索引=隱式排序+有序查詢
缺點:索引建太多的話,會佔儲存空間。索引越多統計資訊越多。寫入會變慢。複製程式碼

2 事務與隔離級別   待續 :《事務與隔離級別》

1 READ_COMMITTED_SNAPSHOT隔離級別 可以解決讀寫互斥
缺點:一次update,tempdb存一份之前的資料,這是update的效能取決於tempdb的IO。如果tempdb在一個爛磁碟上,那麼就涼涼了
2 with nolock: 是一種不請求鎖的機制。
缺點: 查詢有髒資料。不過呢,如果不care髒資料,可以使用。複製程式碼

3 T-sql 儲存過程化

減少重編譯
遇到邏輯修改,直接修改db,不需要程式再次釋出,節約人力和時間雙重成本複製程式碼

4 科學設計表結構, 表結構是根本.

一個好的表結構:
1 避免資料傾斜,進而避免引數嗅探
2 後期易n次迭代開發
3 易維護與優化複製程式碼

5 適當反正規化 

我們遵守資料庫第三正規化的同時,應該考慮適當反正規化,減少過多的表關聯複製程式碼

6 熱點表的優待

1 熱點表應放在吞吐好的磁碟
2 同時設定檔案組,將資料檔案分配到不同磁碟,以避免IO瓶頸複製程式碼

7 tempdb的優待     待續《tempdb的作用》

同理,tempdb資料庫也應該放在效能好的磁碟,避免tempdb檔案頭爭用複製程式碼

四例子

經典查詢:分頁

1 多條件搜尋,應該使用動態sql。拼接sql
2 使用動態sql 需要注意:sql注入
3 根據引數是否傳入,拼接join表,以及where條件——應使用case when 應付多變性

CREATE PROC [dbo].[SP_GET_Person] 
@ZoneID INT=NULL,@Name VARCHAR(50)=NULL,@RoomNo VARCHAR(50)=NULL,@StartNum INT=0,@EndNum INT=10

AS
BEGIN 
  DECLARE @Sql NVARCHAR(MAX); 
  DECLARE @Sql_TotalCount NVARCHAR(MAX); --檢索返回的總數
  DECLARE @Sql_Paged NVARCHAR(MAX); --分頁
  DECLARE @Sql_Common NVARCHAR(MAX);--總數和分頁邏輯相同的sql指令碼(表join和where條件)
  -----總數-----
  SET @Sql_TotalCount=N'
  DECLARE @TotalCount INT;
  SELECT @TotalCount=COUNT(*)'

  SET @Sql_Common=N' FROM [dbo].[EST_House] HH'
  
  +CASE WHEN @ZoneID IS NOT NULL OR @Name IS NOT NULL
  THEN '	
  JOIN [dbo].[EEEE] E
  ON HH.ID=E.ID'
  ELSE '' END

  +CASE WHEN @ZoneID IS NOT NULL THEN
  'JOIN [dbo].[Zone] K
  ON E.ZoneID=K.ZoneID'
  ELSE '' END

  +' WHERE HH.IsDelete = 0 AND HH.IsRecycleBin = 0'
  
  +CASE WHEN @ZoneID IS NOT NULL THEN
  ' AND K.ZoneID =@VAR_ZoneID'
  ELSE '' END 
  +CASE WHEN @Name IS NOT NULL THEN
  ' AND E.Name LIKE ''%''+@VAR_Name+''%'''
  ELSE '' END
  +CASE WHEN @RoomNo IS NOT NULL THEN
  ' AND HH.RoomNo LIKE ''%''+@VAR_RoomNo+''%'''
  ELSE '' END
  
  -----分頁-----
  SET @Sql_Paged=N' 
  SELECT TOP(@VAR_EndNum)
  RowNumber=row_number() OVER (ORDER BY HH.updatetime DESC),HH.[House]	
  INTO #Temp1 '+@Sql_Common+N' 
  SELECT * INTO #Temp2 FROM #Temp1 WHERE RowNumber>=@VAR_StartNum;

  SELECT 
  TotalCount=@TotalCount,RowNumber,E.[ZoneID],K.[ZoneName],E.[Name],B.[BuildingName],HH.[RoomNo]
  FROM #Temp2 H 
  JOIN [dbo].[House] HH
  ON H.[HouseID]=HH.[HouseID]
  JOIN [dbo].[EEEE] E
  ON HH.EID=E.EID
  JOIN [dbo].[Zone] K
  ON E.ZoneID=K.ZoneID
  ORDER BY H.RowNumber;
  '
  SET @Sql=@Sql_TotalCount+@Sql_Common+@Sql_Paged

  PRINT @Sql

 
  EXEC SP_EXECUTESQL @Sql,N'
  @VAR_ZoneID INT,@VAR_Name VARCHAR(50),@VAR_RoomNo VARCHAR(50),@VAR_StartNum INT,@VAR_EndNum INT',@VAR_ZoneID=@ZoneID,@VAR_Name=@Name,@VAR_RoomNo=@RoomNo,@VAR_StartNum=@StartNum,@VAR_EndNum=@EndNum


END














GO複製程式碼