RDSSQLServer-最佳實踐-高CPU使用率系列之非SARG查詢
摘要
阿里雲RDS SQL Server客戶遇到最多的一個問題便是高CPU使用率導致導致SQL Server服務響應緩慢,查詢超時,甚至服務掛起僵死。本系列文章第四篇分析非SARG查詢導致CPU的高利用率的解決之道。
問題引入
“鳥啊,你聽說過RDBMS的非SARG查詢語句嗎?我還是今天第一次聽說呢!”。老鳥有些不解的問菜鳥。
“哈哈,鳥哥,孤陋寡聞,土鱉了吧。它可是導致RDBMS資料庫CPU高使用率的又一個重要的原因呢!今天就讓我細細道來。”,菜鳥開始得意忘形起來。”。
場景分析
SARG是Search Argument英文的縮寫形式,非SARG簡單來說就是指查詢謂詞(特別是WHERE字句或者連線操作的ON字句)導致索引失效,查詢優化器無法使用高效的Index Seek操作,退而求其次的使用效率相對較低的Index Scan操作,從而導致了CPU使用率的上升和查詢效能降低。常見的非SARG操作包括在WHERE語句中使用到了標量函式Datediff,Dateadd,Year,Rtrim,Upper,Lower,LIKE完全模糊匹配(格式如LIKE ‘%XXX%’)或者是使用者自定義函式等。
解決方法
解決非SARG查詢的核心思想是通過查詢邏輯的等價改寫或者功能設計層面的優化來避免WHERE語句中使用標量函式,我們僅以以下幾種常見的非SARG操作來舉例說明,其他類推。
DATEDIFF
比如,我們需要查詢出當天的訂單資訊記錄,非SARG的寫法如下(在WHERE語句中使用了Datediff函式):
USE TestDb
GO
CREATE INDEX IX_OrderDate
ON dbo.SalesOrder([OrderDate])
WITH (FILLFACTOR = 90);
GO
SET STATISTICS TIME ON
SET STATISTICS IO ON
-- find out sales info of today.
SELECT
ItemID, OrderQty, Price,OrderDate
FROM dbo.SalesOrder
WHERE DATEDIFF(DAY, OrderDate, GETDATE()) = 0
SET STATISTICS TIME OFF
SET STATISTICS IO OFF
從效能指標來看,I/O消耗為8406,CPU消耗為171毫秒,執行時間消耗為211毫秒,截圖如下所示:
執行計劃視窗,SQL Server優化器選擇走Index Scan,截圖如下:
其實,我們可以換個思維邏輯想想,當天的資料,其實是指時間大於等於當天凌晨零點零分,並且時間小於等於當前時刻的記錄。那麼等價邏輯的改寫程式碼如下:
USE TestDb
GO
SET STATISTICS TIME ON
SET STATISTICS IO ON
DECLARE
@today DATETIME = CONVERT(CHAR(10), GETDATE(), 120)
;
SELECT
ItemID, OrderQty, Price,OrderDate
FROM dbo.SalesOrder
WHERE OrderDate >= CONVERT(CHAR(10), GETDATE(), 120)
AND OrderDate <= GETDATE();
SET STATISTICS TIME OFF
SET STATISTICS IO OFF
優化後效能指標,I/O消耗為3,CPU消耗為0毫秒,執行時間消耗為109毫秒。
查詢優化器選擇了更為高效的Index Seek的執行計劃操作上來,截圖如下:
從效能指標對比來看,I/O從8406降低到3,CPU消耗從171毫秒降低到0毫秒,執行時間從211降低到109毫秒,特別是I/O和CPU的提升非常明顯。
UPPER/LOWER
由於SQL Server預設的排序規則是忽略大小寫的,換句話說SQL Server認為UPPER和upper是相等的。所以在做字串比較運算的時候,可以省略UPPER或者是LOWER函式的使用,以免造成非SARG查詢,導致CPU使用率增加。
當然需要特別注意的是:在改寫非SARG查詢之前需要再次確認你的資料庫是忽略大小寫的,即含有case-insensitive關鍵字。檢查方法如下:
USE TestDb
GO
EXEC sys.sp_helpsort
結果展示如下圖所示:
RTRIM
有的人在寫字串比較的時候,喜歡使用RTRIM函式來取消字串最右邊的空格後再來比較,其實這種做法是畫蛇添足,完全沒有必要的。理由是SQL Server在做字串比較的時候,自動會忽略最右邊的空格。這樣做反而會導致非SARG查詢,CPU使用率增高。
我們可以寫一個非常簡單的例子來證明這一點,在IF語句中,等號左邊的RTRIM後緊跟一個空格符,等號右邊的字串TRIM後不包括空格,但是IF語句的判斷結果為真。程式碼如下所示:
IF `TRIM ` = `TRIM`
PRINT `equals`
ELSE
PRINT `not equal`
結果展示如下圖所示:
LIKE完全模糊匹配
WHERE語句中的LIKE完全模糊匹配,同樣會導致SQL Server索引失效,同樣也是屬於非SARG查詢的一種。這種場景的優化包含兩種方法:第一種方法是從設計層面來優化,比如:我們經常碰到的場景是通過電話號碼來完全模糊查詢,但是客戶的查詢語句往往傳入的電話號碼又都是一個完整的電話號碼。所以這裡,我們完全可以將設計修改為電話號碼僅支援完整電話號碼查詢,即將LIKE完全模糊匹配的設計修改成了等於操作方式,避免了非SARG操作;第二種解決方法:如果設計層面無法避免要使用完全模糊匹配查詢,可以選擇使用SQL Server Fulltext技術來解決LIKE字句完全模糊查詢,以此來避免非SARG操作,降低CPU使用率。詳情,可以參見文章:SQL Server FullText解決Like字句效能問題
總結
本篇文章分析了非SARG查詢語句導致RDS SQL Server CPU使用率增高的原因以及解決這類問題的核心思想是改寫語義邏輯,避免非SARG查詢導致CPU高使用率,並且舉例說明了幾個典型的非SARG查詢的改寫方法。
相關文章
- dart系列之:集合使用最佳實踐Dart
- dart系列之:dart程式碼最佳實踐Dart
- Java程式CPU使用率高排查Java
- CPU使用率低負載高負載
- 實踐006-elasticsearch查詢之1-URI Search查詢Elasticsearch
- FFmpeg應用實踐之命令查詢
- cpu使用率過高問題(Java)Java
- .netcore利用perf分析高cpu使用率NetCore
- Linux系列之查詢命令Linux
- 實踐007-elasticsearch查詢之2-Request Body與DSL查詢Elasticsearch
- 中後臺專案 - 查詢表格業務最佳實踐
- Elasticsearch從0到千萬級資料查詢實踐(非轉載)Elasticsearch
- 架構師必備:多維度查詢的最佳實踐架構
- dart系列之:手寫Library,Library編寫最佳實踐Dart
- Oracle CPU使用率過高問題處理Oracle
- dart系列之:和null說再見,null使用最佳實踐DartNull
- oracle表空間使用率查詢Oracle
- MySQL入門系列:查詢簡介(七)之組合查詢MySql
- mysql多條件過濾查詢之mysq高階查詢MySql
- win10怎麼減少cpu使用率_win10cpu使用率過高的解決方法Win10
- pt-tools系列:xtrabackup最佳實踐
- 並查集系列之「思路最佳化」並查集
- 千萬級資料深分頁查詢SQL效能最佳化實踐SQL
- 【UNDO】Oracle undo表空間使用率過高,因為一個查詢Oracle
- 【Azure Developer】通過Azure提供的Azue Java JDK 查詢虛擬機器的CPU使用率和記憶體使用率DeveloperJavaJDK虛擬機記憶體
- Mysql 慢查詢優化實踐MySql優化
- CPU 使用率低高負載的原因,看看這篇!負載
- 效能分析(2)- 應用程式 CPU 使用率過高案例
- 小米 A/B 實驗場景基於 Apache Doris 的查詢提速最佳化實踐Apache
- [譯] 程式碼審查之最佳實踐
- Kubernetes叢集健康檢查最佳實踐
- 查詢最佳化——查詢樹結構
- 高階查詢
- 雲原生最佳實踐系列 7:基於 OSS Object FC 實現非結構化檔案實時處理Object
- 前端乾貨之JS最佳實踐前端JS
- PHP最佳實踐之資料庫PHP資料庫
- MSSQL-最佳實踐-使用非對稱金鑰實現列加密SQL加密
- 資料庫高階查詢之子查詢資料庫
- 案例:系統的 CPU 使用率很高,但為啥卻找不到高 CPU 的應用?