引言: 以前在面試的過程中,總有面試官問道:你做過sql性能優化嗎?對此,我的答覆是沒有。一次沒有不是自己的錯誤,兩次也不是,但如果是多次呢?今天痛下決心,把有關sql性能優化的相關知識總結一下,以便在不久的將來,我的回答不是“沒有”,總能多多少少說一些東西。算是長進吧。說到性能優化,本人感覺到有必 ...
引言:
以前在面試的過程中,總有面試官問道:你做過sql性能優化嗎?對此,我的答覆是沒有。一次沒有不是自己的錯誤,兩次也不是,但如果是多次呢?今天痛下決心,把有關sql性能優化的相關知識總結一下,以便在不久的將來,我的回答不是“沒有”,總能多多少少說一些東西。算是長進吧。說到性能優化,本人感覺到有必要先瞭解sql語句的執行順序,因為對優化或多或少的會有些幫助。
sql語句執行順序:
sql語句和其他相關的編程語言最大不同的地方應該是執行順序。對於大多數編程語言來說都是按照順序進行執行,但對於sql語句,儘管select是最開始出現,但幾乎總是最後一個執行,最開始執行的往往是from子句。每一步驟產生一個虛擬表,這些虛擬表對於調用者來說是不能用的,僅僅作用於下一步驟,而只有最後的查詢結果表才能被調用者所使用。當有步驟沒有出現時便跳過該執行步驟。下麵上代碼:
(8)SELECT (9)DISTINCT (11)<Top Num> <select list> (1)FROM [left_table] (3)<join_type> JOIN <right_table> (2) ON <join_condition> (4)WHERE <where_condition> (5)GROUP BY <group_by_list> (6)WITH <CUBE | RollUP> (7)HAVING <having_condition> (10)ORDER BY <order_by_list>
邏輯查詢處理階段簡介:
1)from:對FROM子句中的前兩個表執行笛卡爾積(Cartesian product)(交叉聯接),生成虛擬表VT1
2)on:對VT1應用ON篩選器。只有那些使<join_condition>為真的行才被插入VT2
3)outer(join):如 果指定了OUTER JOIN(相對於CROSS JOIN 或(INNER JOIN),保留表(preserved table:左外部聯接把左表標記為保留表,右外部聯接把右表標記為保留表,完全外部聯接把兩個表都標記為保留表)中未找到匹配的行將作為外部行添加到 VT2,生成VT3.如果FROM子句包含兩個以上的表,則對上一個聯接生成的結果表和下一個表重覆執行步驟1到步驟3,直到處理完所有的表為止。
4)where:對VT3應用WHERE篩選器。只有使<where_condition>為true的行才被插入VT4.
5)group by:按GROUP BY子句中的列列表對VT4中的行分組,生成VT5.
6)cube|roolup:把超組(Suppergroups)插入VT5,生成VT6.
7)having:對VT6應用HAVING篩選器。只有使<having_condition>為true的組才會被插入VT7.
8)select:處理SELECT列表,產生VT8.
9)distinct:將重覆的行從VT8中移除,產生VT9.
10)order by:將VT9中的行按ORDER BY 子句中的列列表排序,生成游標(VC10)
11)top:從VC10的開始處選擇指定數量或比例的行,生成表VT11,並返回調用者。
註:
步驟10,按ORDER BY子句中的列列表排序上步返回的行,返回游標VC10.這一步是第一步也是唯一一步可以使用SELECT列表中的列別名的步驟。這一步不同於其它步驟的 是,它不返回有效的表,而是返回一個游標。SQL是基於集合理論的。集合不會預先對它的行排序,它只是成員的邏輯集合,成員的順序無關緊要。對錶進行排序 的查詢可以返回一個對象,包含按特定物理順序組織的行。ANSI把這種對象稱為游標。理解這一步是正確理解SQL的基礎。
因為這一步不返回表(而是返回游標),使用了ORDER BY子句的查詢不能用作表表達式。表表達式包括:視圖、內聯表值函數、子查詢、派生表和共用表達式。它的結果必須返回給期望得到物理記錄的客戶端應用程式。
在SQL中,表表達式中不允許使用帶有ORDER BY子句的查詢,而在T—SQL中卻有一個例外(應用TOP選項)。所以要記住,不要為表中的行假設任何特定的順序。換句話說,除非你確定要有序行,否則不要指定ORDER BY 子句。排序是需要成本的,SQL Server需要執行有序索引掃描或使用排序運行符。
sql語句執行時是按照從右到左的順序處理from子句中的表名,from子句中寫在最後的表也即是基礎表將被最先處理,因此在from子句中包含多個表的情況下,選擇記錄條數最少的表作為基礎表,在某種程度上將會極大的提高其性能。如果有3個以上的表,則選擇交叉表作為基礎表。此處對性能優化來說相當重要。
執行計劃:
說完執行順序後,便討論下執行計劃:
執行計劃是資料庫根據SQL語句和相關表的統計信息作出的一個查詢方案,這個方案是由查詢優化器自動分析產生的,比如一條SQL語句如果用來從一個 10萬條記錄的表中查1條記錄,那查詢優化器會選擇“索引查找”方式,如果該表進行了歸檔,當前只剩下5000條記錄了,那查詢優化器就會改變方案,採用 “全表掃描”方式。
可見,執行計劃並不是固定的,它是“個性化的”。產生一個正確的“執行計劃”有兩點很重要:
(1) SQL語句是否清晰地告訴查詢優化器它想乾什麼?
(2) 查詢優化器得到的資料庫統計信息是否是最新的、正確的?
優化檢測工具:
基礎知識介紹完畢了,開始性能優化,但是我們怎麼才能知道該系統中的那些sql語句應該進行性能優化,該語句是否應該進行系統優化,查看相關資料,針對sqlserver,找到sqlserver資料庫對應的有個sql server profiler,使用該工具可以找到針對某個資料庫表來說,有什麼樣的操作行為拉低了其性能。
打開系統主菜單--sqlserver幾---性能工具--->>sql server profiler;
然後文件--新建跟蹤--顯示跟蹤屬性視窗;
首先那個select%是個篩選監測的TextData。那個%是個通配符,他的意思就是篩選select開口的語句。當然這你自己可以隨便定義,如update%,delete%....。
把那個排除不包含值的行也給帶上,然後確定,運行。然後在資料庫中運行一句select。你會發現他檢測到啦。
1.查找持續時間最長的查詢
一般情況下,最長查詢時間的查詢語句就是最影響性能的原因存在。它不僅占用資料庫引擎大量的時間,還浪費系統資源,還影響資料庫應用系統的交互速度。再對數據用應用系統進行優化時,先找出他,對其優化,在創建跟蹤時,勾上TSQL-SQL:BatchCompleted.跟Stored Procedures-RPC:completed。這樣就能找出來這個最長時間查詢然後對其進行分析優化。
select TextData,Duration,CPU from <跟蹤的表> where EventClass=12 -- 等於12表示BatchCompleted事件 and CPU<(0.4*Duration) --如果cpu的占用時間,小於執行sql語句時間的40%,說明該語句等待時間過長
2.最占用系統資源的查詢
就是占用cpu時間,跟讀寫IO的次數。建議事件包含Connect、Disconnect、ExistingConnection、SQL:BatchCompleted、RPC:completed,列包含writes,reads,cpu。
3.檢測死鎖
在訪問量,併發量都很大的資料庫中,如果設計稍不合理,就有可能造成死鎖,給系統性能帶來影響。事件包含:RPC:Starting、SQL:BatchStarting、Lock:DeadLock(死鎖事件)、Lock:DeadLockChaining(死鎖的事件序列)。
資料庫引擎優化顧問
和sql server profiler相對於的有個“資料庫引擎優化顧問”,也是一個與性能優化有關的工具,可以抽時間瞭解瞭解。瞭解後再補充吧。
sql性能優化常見經驗:
下麵總結下載網上各個大牛們認為進行sql優化應該操作的事項:
1、模糊查詢like。
使用like進行模糊查詢時應該特別註意,這個很基本,基本上大家都知道。呵呵
select*from contact where username like ‘%yue%’
關鍵詞%yue%,由於yue前面用到了“%”,因此該查詢必然走全表掃描,除非必要,否則不要在關鍵詞前加%。
2、where條件查詢
儘量避免使用in,not in,having,可以使用 exist 和not exist代替 in和not in。不要以字元格式聲明數字,要以數字格式聲明字元值。
3、前面提到的from子句中有多個表進行關聯查詢時
在from子句中包含多個表的情況下,選擇記錄條數最少的表作為基礎表,在某種程度上將會極大的提高其性能。如果有3個以上的表,則選擇交叉表作為基礎表
4、select *查詢
儘量不要使用
select * from tablename
取而代之的則是:
select columnname1,columnname2 from tablename
5、排序操作
避免使用耗費資源的操作,帶有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQL語句會啟動SQL引擎 執行,耗費資源的排序(SORT)功能. DISTINCT需要一次排序操作, 而其他的至少需要執行兩次排序。
6、索引表操作
對於此處,個人還沒有弄明白,首先對於索引還不明白,那麼性能優化更談不上了。反正很多大牛都是操作索引表,需要特別註意。以後明白了再補充吧。
...
7、統一規範sql語句
編寫規範的sql語句,這一點是最重要的一點,不管對於系統還是個人來說,都是相當的重要。
不規範的有:
很複雜的sql語句,對於編寫者自己都暈了。
大小寫隨意編寫,對於系統來說是個小麻煩。
肯定還有,就是平時多註意就ok了。
參考:
SqlServer性能檢測和優化工具使用詳細
高手詳解SQL性能優化十條經驗
優化SQL查詢:如何寫出高性能SQL語句