最近,下面的一個項目遇到緊急問題,我這匹老馬也要和年輕人一起奮鬥一下。問題是當把一倍壓力數據灌入數據庫,很多查詢都奇慢無比。
說道這裏必須要說一下性能問題的基本準則。性能問題Tunning的次序
1)架構設計(軟件架構和數據庫設計,糟糕的設計幾乎是致命的)
2)代碼缺陷(導致性能問題的90%)
3)增加索引(這個是要根據實際情況來確定)
4)資源調優(CPU->內存->Disk IO)
這裏網絡不是考慮因素。
把程序的SQL文拿出來一看,有的一看一堆子查詢構成的JOIN,基本上一眼就可以斷定,需要重寫。我們這個運用系統把SQL文都配置成動態的,這個設計給現在的調優帶來了方便。
突然出現了一個很有趣的現象。有一個查詢很慢(一分鐘纔出來),檢查SQL文。這句SQL文是這樣
SELECT ISNULL(a.CWB_NO,b.CWB_NO) AS CWB_NO,a.IMPORT_AWB_NO, a.IMPORT_BWB_NO,ISNULL(a.PCS,0) AS RS2PCS,ISNULL(b.PCS,0) AS DECPCS,a.CCC_STATUS FROM (SELECT * FROM TB_CWB WHERE IMPORT_AWB_NO = @IMPORT_AWB_NO) a FULL JOIN (SELECT * FROM TP_DECSUMMARY WHERE AWB_NO = @IMPORT_AWB_NO) b ON a.CWB_NO = b.CWB_NO AND b.AVAILABLE = 'Y' WHERE a.AVAILABLE = 'Y' |
FULL JOIN不是問題核心(因爲業務規則就是這樣),也不是SELECT *,其實SELECT *和指定字段或許有差異,但是絕對不會有很大差別。
我在後臺運行了一下,0秒都不到。但是另外一個程序員說同樣運行要59秒。奇怪!!!
拿過來對比一下,就發現差異了。
因爲,我們的系統採取的是用.NET中cmd指定參數的寫法,轉換成後臺sql文,等於運行sp_executesql的方法。更簡單說就是替換變量。
即等價的SQL文應該是
SELECT ISNULL(a.CWB_NO,b.CWB_NO) AS CWB_NO,a.IMPORT_AWB_NO,
a.IMPORT_BWB_NO,ISNULL(a.PCS,0) AS RS2PCS,ISNULL(b.PCS,0) AS DECPCS,a.CCC_STATUS
FROM
(SELECT * FROM TB_CWB WHERE IMPORT_AWB_NO = '25200000011') a
FULL JOIN
(SELECT * FROM TP_DECSUMMARY WHERE AWB_NO ='25200000011') b
ON a.CWB_NO = b.CWB_NO AND b.AVAILABLE = 'Y'
WHERE a.AVAILABLE = 'Y'
而我調試用的替換SQL文
DECLARE @IMPORT_AWB_NO VARCHAR(20)
SET @IMPORT_AWB_NO='25200000011'
SELECT ISNULL(a.CWB_NO,b.CWB_NO) AS CWB_NO,a.IMPORT_AWB_NO,
a.IMPORT_BWB_NO,
ISNULL(a.PCS,0) AS RS2PCS,
ISNULL(b.PCS,0) AS DECPCS,
a.CCC_STATUS
FROM (
SELECT *
FROM TB_CWB
WHERE IMPORT_AWB_NO = @IMPORT_AWB_NO
) a
FULL JOIN (SELECT *
FROM TP_DECSUMMARY
WHERE AWB_NO = @IMPORT_AWB_NO) b
ON a.CWB_NO = b.CWB_NO
AND b.AVAILABLE = 'Y'
WHERE a.AVAILABLE = 'Y'
這個即相當於SP的寫法。
這2句的結果導致就是執行計劃完全不一樣。從而產生天壤之別的效果。這個問題和SQL文的好壞沒有關係。我對比了者2個執行計劃,個人認爲由於SQL Server的CBO分析這個“傻瓜機”失效效應導致。
我們先看一下2種的執行計劃的區別。我用第2種(即SP)方法的執行計劃。
2個執行計劃的唯一差別就是圖中的2個Paralism(數據庫服務器是8個CPU)。即我的那句SQL採用了並行裝載數據的方法。而第一中沒有使用並行裝載。原因很簡單,因爲執行計劃分析器認爲前面這句SQL執行代價很小,而我的執行代價很高。因此進行了區別對待,前者不需要動用硬件資源,後者則需要動用硬件資源。這就是失效效應。而一般認爲慢就是因爲硬件不夠,在這裏充分體現是無稽之談。至少性能問題只有5%甚至更低的情況才和硬件有關。
至於這個代價估算的計算方法,只有查具體的技術文件,大體應該和數據大小,索引大小,邏輯讀寫,物理讀寫,CPU資源有關。因爲是估算,因此有偏差很正常。
那麼解決這個問題,加索引纔是正途。這就是我前面講到的原則。通過加索引,執行計劃發生了變化。見下圖。
增加索引後的速度結果飛快。
Paralism和索引的概念就好比,在南京路上找某戶戶主是王五,Paralism是出動16個警察,而索引就好比一個警察拿戶籍登記冊找。一個是擁有資源多而致勝,一個是工作方法好而致勝。
從這裏可以看出,性能調優起始是一個根據實際情況進行平衡選擇的過程,武斷認爲就是加索引,提升硬件都說明你不了原理。對了也只是運氣好。
總結這個例子,失效效應就是CBO帶來的一個有趣的現象。顯然CBO要用,但是要去學習明白它的原理和特點。就好比傻瓜照相機還是用的人多,但是你要懂得傻瓜機也有判斷失誤的時候,所以要用“白加黑減”的曝光補償。