1、數據庫訪問優化的五個法則程序員
在實際開發,咱們主要是須要對SQL語句進行優化,咱們須要快速定位能性的瓶頸點,也就是說快速找到咱們SQL主要的開銷在哪裏?根據木桶原理能夠知道,最慢的設備每每是性能瓶頸。例如:互聯網運用中的帶寬,本地數據複製時的硬盤的訪問速度。
算法
根據當前計算機硬件的基本性能指標及其在數據庫中主要操做內容,能夠整理出以下五條性能基本優化法則:sql
(1)減小數據訪問(減小磁盤訪問)數據庫
(2)返回更少數據(減小網絡傳輸或磁盤訪問)瀏覽器
(3)減小交互次數(減小網絡傳輸)性能優化
(4)減小服務器CPU開銷(減小CPU及內存開銷)服務器
(5) 利用更多資源(增長資源)網絡
因爲每一層優化法則都是解決其對應硬件的性能問題,因此帶來的性能提高比例也不同。傳統數據庫系統設計是也是儘量對低速設備提供優化方法,所以針對低速設備問題的可優化手段也更多,優化成本也更低。咱們任何一個SQL的性能優化都應該按這個規則由上到下來診斷問題並提出解決方案,而不該該首先想到的是增長資源解決問題。併發
如下是每一個優化法則層級對應優化效果及成本經驗參考:oracle
優化法則 |
性能提高效果 |
優化成本 |
減小數據訪問 |
1~1000 |
低 |
返回更少數據 |
1~100 |
低 |
減小交互次數 |
1~20 |
低 |
減小服務器CPU開銷 |
1~5 |
低 |
利用更多資源 |
@~10 |
高 |
2、數據庫訪問優化法則詳解
2.一、減小數據訪問
(1)正確建立索引
索引有哪些種類?
常見的索引有B-TREE索引、位圖索引、全文索引,位圖索引通常用於數據倉庫應用,全文索引因爲使用較少,這裏不深刻介紹。B-TREE索引包括不少擴展類型,如組合索引、反向索引、函數索引等等,如下是B-TREE索引的簡單介紹:
B-TREE索引也稱爲平衡樹索引(Balance Tree),它是一種按字段排好序的樹形目錄結構,主要用於提高查詢性能和惟一約束支持。B-TREE索引的內容包括根節點、分支節點、葉子節點。
咱們通常在什麼字段上建索引?
這是一個很是複雜的話題,須要對業務及數據充分分析後再能得出結果。主鍵及外鍵一般都要有索引,其它須要建索引的字段應知足如下條件:
1、字段出如今查詢條件中,而且查詢條件可使用索引;
2、語句執行頻率高,一天會有幾千次以上;
3、經過字段條件可篩選的記錄集很小,那數據篩選比例是多少才適合?
這個沒有固定值,須要根據表數據量來評估,如下是經驗公式,可用於快速評估:
小表(記錄數小於10000行的表):篩選比例<10%;
大表:(篩選返回記錄數)<(表總記錄數*單條記錄長度)/10000/16
單條記錄長度≈字段平均內容長度之和+字段數*2
索引對DML(INSERT,UPDATE,DELETE)附加的開銷有多少?
這個沒有固定的比例,與每一個表記錄的大小及索引字段大小密切相關,如下是一個普通表測試數據,僅供參考:
索引對於Insert性能下降56%
索引對於Update性能下降47%
索引對於Delete性能下降29%
所以對於寫IO壓力比較大的系統,表的索引須要仔細評估必要性,另外索引也會佔用必定的存儲空間。
(2)只經過索引訪問數據
有些時候,咱們只是訪問表中的幾個字段,而且字段內容較少,咱們能夠爲這幾個字段單獨創建一個組合索引,這樣就能夠直接只經過訪問索引就能獲得數據,通常索引佔用的磁盤空間比表小不少,因此這種方式能夠大大減小磁盤IO開銷。
(3)優化SQL執行計劃
SQL執行計劃是關係型數據庫最核心的技術之一,它表示SQL執行時的數據訪問算法。因爲業務需求愈來愈複雜,表數據量也愈來愈大,程序員愈來愈懶惰,SQL也須要支持很是複雜的業務邏輯,但SQL的性能還須要提升,所以,優秀的關係型數據庫除了須要支持複雜的SQL語法及更多函數外,還須要有一套優秀的算法庫來提升SQL性能。
2.二、返回更少的數據
減小數據的返回也是優化的重要手段,主要有兩種方法 分頁 和 只返回須要的字段。
(1)分頁
分頁總共包括三種分頁方式:客戶端分頁、服務端分頁、數據庫分頁。
客服端分頁:將數據從應用服務器所有下載到本地應用程序或瀏覽器,在應用程序或瀏覽器內部經過本地代碼進行分頁處理。
優勢:編碼簡單,減小客戶端與應用服務器網絡交互次數
缺點:首次交互時間長,佔用客戶端內存
適應場景:客戶端與應用服務器網絡延時較大,但要求後續操做流暢,如手機GPRS,超遠程訪問(跨國)等等。
服務端分頁:將數據從數據庫服務器所有下載到應用服務器,在應用服務器內部再進行數據篩選。
優勢:編碼簡單,只須要一次SQL交互,總數據與分頁數據差很少時性能較好。
缺點:總數據量較多時性能較差。
適應場景:數據庫系統不支持分頁處理,數據量較小而且可控。
數據庫分頁:採用數據庫SQL分頁須要兩次SQL完成,一個SQL計算總數量,一個SQL返回分頁後的數據。
優勢:性能好
缺點:編碼複雜,各類數據庫語法不一樣,須要兩次SQL交互。
ps:oracle數據庫通常採用rownum來進行分頁。經常使用分頁方式以下
rownum分頁:
select * from ( select a.*,rownum rn from (select * from student a where id=? order by status) a where rownum<=20) where rn>10;
rowid分頁語法:
select b.* from ( select * from ( select a.*,rownum rn from (select rowid rid,status from student a where id=? order by status) a where rownum<=20) where rn>10) a, student b where a.rid=b.rowid;
(2)只返回須要的字段
經過去除沒必要要的返回字段能夠提升性能。
優勢:
1、減小數據在網絡上傳輸開銷
2、減小服務器數據處理開銷
3、減小客戶端內存佔用
4、字段變動時提早發現問題,減小程序BUG
5、若是訪問的全部字段恰好在一個索引裏面,則可使用純索引訪問提升性能。
缺點:增長編碼工做量
2.三、減小交互的次數
(1) batch 操做
數據庫訪問框架通常都提供了批量提交的接口,jdbc支持batch的提交處理方法,咱們能夠批量插入、更新和刪除數據。這樣交互次數大大減小。採用batch操做通常不會減小不少數據庫服務器的物理IO,可是會大大減小客戶端與服務端的交互次數,從而減小了屢次發起的網絡延時開銷,同時也會下降數據庫的CPU開銷。
(2)in
不少時候咱們須要按一些ID查詢數據庫記錄,咱們能夠採用一個ID一個請求發給數據庫,以下所示:
for :var in ids[] do begin select * from mytable where id=:var; end;
咱們也能夠作一個小的優化, 以下所示,用ID INLIST的這種方式寫SQL:
select * from mytable where id in(:id1,id2,...,idn);
經過這樣處理能夠大大減小SQL請求的數量,從而提升性能。那若是有10000個ID,那是否是所有放在一條SQL裏處理呢?答案確定是否認的。首先大部份數據庫都會有SQL長度和IN裏個數的限制,如ORACLE的IN裏就不容許超過1000個值。
另外當前數據庫通常都是採用基於成本的優化規則,當IN數量達到必定值時有可能改變SQL執行計劃,從索引訪問變成全表訪問,這將使性能急劇變化。隨着SQL中IN的裏面的值個數增長,SQL的執行計劃會更復雜,佔用的內存將會變大,這將會增長服務器CPU及內存成本。
評估在IN裏面一次放多少個值還須要考慮應用服務器本地內存的開銷,有併發訪問時要計算本地數據使用週期內的併發上限,不然可能會致使內存溢出。
綜合考慮,通常IN裏面的值個數超過20個之後性能基本沒什麼太大變化,也特別說明不要超過100,超事後可能會引發執行計劃的不穩定性及增長數據庫CPU及內存成本.
(3)設置Fetch Size
當咱們採用select從數據庫查詢數據時,數據默認並非一條一條返回給客戶端的,也不是一次所有返回客戶端的,而是根據客戶端fetch_size參數處理,每次只返回fetch_size條記錄,當客戶端遊標遍歷到尾部時再從服務端取數據,直到最後所有傳送完成。因此若是咱們要從服務端一次取大量數據時,能夠加大fetch_size,這樣能夠減小結果數據傳輸的交互次數及服務器數據準備時間,提升性能。
2.四、減小數據庫服務器CPU運算
(1) 使用綁定變量
Java中Preparestatement就是爲處理綁定變量提供的對像,綁定變量有如下優勢:
1、防止SQL注入
2、提升SQL可讀性
3、提升SQL解析性能,不使用綁定變動咱們通常稱爲硬解析,使用綁定變量咱們稱爲軟解析。
(2)合理使用排序
(3)減小比較操做
(4)大量複雜運算在客戶端處理
2.五、利用更多的資源
(1)客戶端多進程並行訪問
多進程並行訪問是指在客戶端建立多個進程(線程),每一個進程創建一個與數據庫的鏈接,而後同時向數據庫提交訪問請求。當數據庫主機資源有空閒時,咱們能夠採用客戶端多進程並行訪問的方法來提升性能。若是數據庫主機已經很忙時,採用多進程並行訪問性能不會提升,反而可能會更慢。因此使用這種方式最好與DBA或系統管理員進行溝通後再決定是否採用。
(2)數據庫並行處理