SQLServer 常見高CPU利用率原因


1.缺失索引:

 USE AdventureWorks2014
 SET STATISTICS TIME ON;
 SET STATISTICS IO ON ;
 SELECT per.FirstName,per.LastName,p.Name,p.ProductNumber,soh.OrderDate,sod.LineTotal,soh.TotalDue
 FROM sales.SalesOrderHeader AS soh
 INNER JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID=sod.SalesOrderID
 INNER JOIN Production.Product AS p ON sod.ProductID=p.ProductID
 INNER JOIN sales.Customer AS c ON soh.CustomerID=c.CustomerID
 INNER JOIN Person.Person AS per ON c.PersonID=per.BusinessEntityID
 WHERE sod.LineTotal>25000

 SET STATISTICS IO OFF;
 SET STATISTICS TIME OFF;

 得到下面的信息:

SQL Server 執行時間:
   CPU 時間 = 63 毫秒,占用時間 = 378 毫秒。
 SQL Server 執行時間:
   CPU 時間 = 0 毫秒,占用時間 = 0 毫秒。

  --創建一個索引

 CREATE NONCLUSTERED INDEX idx_SalesOrderDetail_LineTotal ON sales.SalesOrderDetail(LineTotal)

 索引后結果如下:

 SQL Server 執行時間:
   CPU 時間 = 0 毫秒,占用時間 = 0 毫秒。

 SQL Server 執行時間:
   CPU 時間 = 0 毫秒,占用時間 = 0 毫秒。

 2.統計信息過時

你明知道返回和處理的結果集都很小,而優化器卻選擇了hash連接,這是就可以檢查一下圖形化執行計划中是否有黃色嘆號,或者用文本化執行計划看看預估和實際行數的差異是否很大。如果是使用UPDATE STATISTICS語句更新統計信息,同時檢查為什么統計信息過時

3.非SARG查詢

如果是一個謂詞(特別是Where條件中)能用到索引查找操作,就可以理解為SARG,

如果在where 條件所用到的列中使用了標量函數(YEAR、UPPER)或使用like ‘%%’這類的查詢,稱為非SARG查詢會導致索引無效

 --非SARG(聚集索引掃描)
 SELECT soh.SalesOrderID,soh.OrderDate,soh.DueDate,soh.ShipDate,soh.Status,soh.SubTotal,soh.TaxAmt,soh.Freight,soh.TotalDue
  FROM sales.SalesOrderHeader AS soh
 INNER JOIN sales.SalesOrderDetail AS sod
 ON soh.SalesOrderID=sod.SalesOrderID 
 WHERE CONVERT(DATE,sod.ModifiedDate)='07/01/2005'

進行改寫:(聚集索引查找)

  SELECT soh.SalesOrderID,soh.OrderDate,soh.DueDate,soh.ShipDate,soh.Status,soh.SubTotal,soh.TaxAmt,soh.Freight,soh.TotalDue
  FROM sales.SalesOrderHeader AS soh
 INNER JOIN sales.SalesOrderDetail AS sod
 ON soh.SalesOrderID=sod.SalesOrderID 
 WHERE  sod.ModifiedDate>='2005-07-01 00:00:00.000'
 AND sod.ModifiedDate<'2005-07-02 00:00:00.000'

 非SARG對where條件中的列使用UPPER/LTRIM/ISNULL之類的標量函數,對於這種情況,改寫查詢解決。

4.隱式轉換

指一個查詢From/Where子句中,用於關聯和判斷列之間數據類型不同,導致優化器需要根據數據類型的優先級高低進行類型轉換然后在優化、執行。

 SELECT p.FirstName,p.LastName,c.AccountNumber FROM Sales.Customer AS c 
  INNER JOIN Person.Person AS p 
  ON c.PersonID =p.BusinessEntityID
  WHERE c.AccountNumber=N'AW00029594'

如上圖加寬部分就是需要把varchar類型轉換成nvarchar類型。可以考慮在傳入where條件之前先進行顯式數據類型轉換。

 5.參數嗅探

創建針對存儲過程、函數或者參數化查詢的執行計划時,根據傳入的參數進行預估並生成執行計划的一個功能,參數嗅探出現在執行計划的編譯或者重編譯過程中。

CREATE PROCEDURE user_GetCustomerShipDates
  (
  @ShipDateStart Datetime,
  @ShipDateEnd datetime
  )
  AS 
  SELECT CustomerID,SalesOrderNumber
   FROM Sales.SalesOrderHeader 
   WHERE ShipDate BETWEEN @ShipDateStart AND @ShipDateEnd

   --創建非聚集索引
   CREATE NONCLUSTERED INDEX IDX_ShipDate_ASC
   ON Sales.SalesOrderHeader(ShipDate)

   --清空緩存
   DBCC FREEPROCCACHE
   EXEC user_GetCustomerShipDates '2005/07/08','2008/01/01'
   EXEC user_GetCustomerShipDates '2005/07/10','2008/07/20'

   --刪除索引
   drop index IDX_ShipDate_ASC  on  Sales.SalesOrderHeader 

 在ShipDate上有索引,還是進行了聚集索引掃描。

在第一個存儲過程的參數中,查詢條件的時間范圍幾乎包括了全表的所有時間,另外非聚集索引沒有覆蓋查詢,因此使用了聚集索引掃描

第二個存儲過程仍然會用上面的執行計划。

把存儲過程的順序調換一下:(執行計划)

 

 對於參數嗅探問題,可以使用部分編譯、編譯提示等功能來避免,更多的優化應該考慮數據和研究數據分布問題

 6.--非參數化Ad—hoc查詢

Ad-hoc稱為即席查詢,可以理解為沒有使用存儲過程、SP_Executesql或其他方式強制預定義SQL語句。

如:SELECT * FROM bt WHERE id=***這類查詢引起的問題

 可以把:高級--真對即席工作負荷進行優化:true

或者在數據庫層面強制參數化:

 ALTER DATABASE AdventureWorks2014 SET PARAMETERIZATION FORCED

 7.非必要的並行查詢

並行操作會把一個查詢分開到多個線程中執行,然后在合並到一起返回結果

 

數據庫事務:

事務是對數據庫操作的單元,可以是一個Select語句,也可以是包好多個Select、Update、Delete、Insert的操作的命名集合

1.原子性:意味着一個事務內的所有操作必須全部完成或者全部回滾。

2.一致性:要求整個事務在運行的前后數據庫的狀態必須一致,不能打破數據定義中的一致性約束

3.隔離性:保證同一時間中,一個事務的運行不能被另一個事務影響。

4.持久性:事務一旦提交成功,將永久存儲到服務器的文件系統中,即使系統在中途奔潰,所發生的的效果都不會丟失,這個會通過日志來保證。

顯示事務隱式事務(區別在於創建和提交的方式)

隱式事務:由SQL Server自己去開啟和提交/回滾,並且在內部保證ACID特性。

顯示事務:以Begin Tran/Transaction開始以Commit Tran/Transaction 或者Rollback Tran結束


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM