mysql 和Oracle的資料庫詳解效能優化
出處:
1.資料庫訪問優化法則
要正確的優化SQL,我們需要快速定位能性的瓶頸點,也就是說快速找到我們SQL主要的開銷在哪裡?而大多數情況效能最慢的裝置會是瓶頸點,如下載時網路速度可能會是瓶頸點,本地複製檔案時硬碟可能會是瓶頸點,為什麼這些一般的工作我們能快速確認瓶頸點呢,因為我們對這些慢速裝置的效能資料有一些基本的認識,如網路頻寬是2Mbps,硬碟是每分鐘7200轉等等。因此,為了快速找到SQL的效能瓶頸點,我們也需要了解我們計算機系統的硬體基本效能指標,下圖展示的當前主流計算機效能指標資料。
從圖上可以看到基本上每種裝置都有兩個指標:
延時(響應時間):表示硬體的突發處理能力;
頻寬(吞吐量):代表硬體持續處理能力。
從上圖可以看出,計算機系統硬體效能從高到代依次為:
CPU——Cache(L1-L2-L3)——記憶體——SSD硬碟——網路——硬碟
由於SSD硬碟還處於快速發展階段,所以本文的內容不涉及SSD相關應用系統。
根據資料庫知識,我們可以列出每種硬體主要的工作內容:
CPU及記憶體:快取資料訪問、比較、排序、事務檢測、SQL解析、函式或邏輯運算;
網路:結果資料傳輸、SQL請求、遠端資料庫訪問(dblink);
硬碟:資料訪問、資料寫入、日誌記錄、大資料量排序、大表連線。
根據當前計算機硬體的基本效能指標及其在資料庫中主要操作內容,可以整理出如下圖所示的效能基本優化法則:
這個優化法則歸納為5個層次:
1、 減少資料訪問(減少磁碟訪問)
2、 返回更少資料(減少網路傳輸或磁碟訪問)
3、 減少互動次數(減少網路傳輸)
4、 減少伺服器CPU開銷(減少CPU及記憶體開銷)
5、 利用更多資源(增加資源)
由於每一層優化法則都是解決其對應硬體的效能問題,所以帶來的效能提升比例也不一樣。傳統資料庫系統設計是也是儘可能對低速裝置提供優化方法,因此針對低速裝置問題的可優化手段也更多,優化成本也更低。我們任何一個SQL的效能優化都應該按這個規則由上到下來診斷問題並提出解決方案,而不應該首先想到的是增加資源解決問題。
以下是每個優化法則層級對應優化效果及成本經驗參考:
優化法則 | 效能提升效果 | 優化成本 |
減少資料訪問 | 1~1000 | 低 |
返回更少資料 | 1~100 | 低 |
減少互動次數 | 1~20 | 低 |
減少伺服器CPU開銷 | 1~5 | 低 |
利用更多資源 | @~10 | 高 |
接下來,我們針對5種優化法則列舉常用的優化手段並結合例項分析。
資料塊是資料庫中資料在磁碟中儲存的最小單位,也是一次IO訪問的最小單位,一個數據塊通常可以儲存多條記錄,資料塊大小是DBA在建立資料庫或表空間時指定,可指定為2K、4K、8K、16K或32K位元組。下圖是一個Oracle資料庫典型的物理結構,一個數據庫可以包括多個數據檔案,一個數據檔案內又包含多個數據塊;
ROWID
ROWID是每條記錄在資料庫中的唯一標識,通過ROWID可以直接定位記錄到對應的檔案號及資料塊位置。ROWID內容包括檔案號、對像號、資料塊號、記錄槽號,如下圖所示:
三、資料庫訪問優化法則詳解
1、減少資料訪問
1.1、建立並使用正確的索引
資料庫索引的原理非常簡單,但在複雜的表中真正能正確使用索引的人很少,即使是專業的DBA也不一定能完全做到最優。
索引會大大增加表記錄的DML(INSERT,UPDATE,DELETE)開銷,正確的索引可以讓效能提升100,1000倍以上,不合理的索引也可能會讓效能下降100倍,因此在一個表中建立什麼樣的索引需要平衡各種業務需求。
索引常見問題:
索引有哪些種類?
常見的索引有B-TREE索引、點陣圖索引、全文索引,點陣圖索引一般用於資料倉庫應用,全文索引由於使用較少,這裡不深入介紹。B-TREE索引包括很多擴充套件型別,如組合索引、反向索引、函式索引等等,以下是B-TREE索引的簡單介紹:
B-TREE索引也稱為平衡樹索引(Balance Tree),它是一種按欄位排好序的樹形目錄結構,主要用於提升查詢效能和唯一約束支援。B-TREE索引的內容包括根節點、分支節點、葉子節點。
葉子節點內容:索引欄位內容+表記錄ROWID
根節點,分支節點內容:當一個數據塊中不能放下所有索引欄位資料時,就會形成樹形的根節點或分支節點,根節點與分支節點儲存了索引樹的順序及各層級間的引用關係。
一個普通的BTREE索引結構示意圖如下所示:
如果我們把一個表的內容認為是一本字典,那索引就相當於字典的目錄,如下圖所示:
圖中是一個字典按部首+筆劃數的目錄,相當於給字典建了一個按部首+筆劃的組合索引。
一個表中可以建多個索引,就如一本字典可以建多個目錄一樣(按拼音、筆劃、部首等等)。
一個索引也可以由多個欄位組成,稱為組合索引,如上圖就是一個按部首+筆劃的組合目錄。
SQL什麼條件會使用索引?
當欄位上建有索引時,通常以下情況會使用索引:
INDEX_COLUMN = ?
INDEX_COLUMN > ?
INDEX_COLUMN >= ?
INDEX_COLUMN < ?
INDEX_COLUMN <= ?
INDEX_COLUMN between ? and ?
INDEX_COLUMN in (?,?,...,?)
INDEX_COLUMN like ?||'%'(後導模糊查詢)
T1. INDEX_COLUMN=T2. COLUMN1(兩個表通過索引欄位關聯)
SQL什麼條件不會使用索引?
查詢條件 | 不能使用索引原因 |
INDEX_COLUMN <> ? INDEX_COLUMN not in (?,?,...,?) | 不等於操作不能使用索引 |
function(INDEX_COLUMN) = ? INDEX_COLUMN + 1 = ? INDEX_COLUMN || 'a' = ? | 經過普通運算或函式運算後的索引欄位不能使用索引 |
INDEX_COLUMN like '%'||? INDEX_COLUMN like '%'||?||'%' | 含前導模糊查詢的Like語法不能使用索引 |
INDEX_COLUMN is null | B-TREE索引裡不儲存欄位為NULL值記錄,因此IS NULL不能使用索引 |
NUMBER_INDEX_COLUMN='12345' CHAR_INDEX_COLUMN=12345 | Oracle在做數值比較時需要將兩邊的資料轉換成同一種資料型別,如果兩邊資料型別不同時會對欄位值隱式轉換,相當於加了一層函式處理,所以不能使用索引。 |
a.INDEX_COLUMN=a.COLUMN_1 | 給索引查詢的值應是已知資料,不能是未知欄位值。 |
注: 經過函式運算欄位的欄位要使用可以使用函式索引,這種需求建議與DBA溝通。 有時候我們會使用多個欄位的組合索引,如果查詢條件中第一個欄位不能使用索引,那整個查詢也不能使用索引 如:我們company表建了一個id+name的組合索引,以下SQL是不能使用索引的 Select * from company where name=? Oracle9i後引入了一種index skip scan的索引方式來解決類似的問題,但是通過index skip scan提高效能的條件比較特殊,使用不好反而效能會更差。 |
我們一般在什麼欄位上建索引?
這是一個非常複雜的話題,需要對業務及資料充分分析後再能得出結果。主鍵及外來鍵通常都要有索引,其它需要建索引的欄位應滿足以下條件:
1、欄位出現在查詢條件中,並且查詢條件可以使用索引;
2、語句執行頻率高,一天會有幾千次以上;
3、通過欄位條件可篩選的記錄集很小,那資料篩選比例是多少才適合?
這個沒有固定值,需要根據表資料量來評估,以下是經驗公式,可用於快速評估:
小表(記錄數小於10000行的表):篩選比例<10%;
大表:(篩選返回記錄數)<(表總記錄數*單條記錄長度)/10000/16
單條記錄長度≈欄位平均內容長度之和+欄位數*2
以下是一些欄位是否需要建B-TREE索引的經驗分類:
欄位型別 | 常見欄位名 | |
需要建索引的欄位 | 主鍵 | ID,PK |
外來鍵 | PRODUCT_ID,COMPANY_ID,MEMBER_ID,ORDER_ID,TRADE_ID,PAY_ID | |
有對像或身份標識意義欄位 | HASH_CODE,USERNAME,IDCARD_NO,EMAIL,TEL_NO,IM_NO | |
索引慎用欄位,需要進行資料分佈及使用場景詳細評估 | 日期 | GMT_CREATE,GMT_MODIFIED |
年月 | YEAR,MONTH | |
狀態標誌 | PRODUCT_STATUS,ORDER_STATUS,IS_DELETE,VIP_FLAG | |
型別 | ORDER_TYPE,IMAGE_TYPE,GENDER,CURRENCY_TYPE | |
區域 | COUNTRY,PROVINCE,CITY | |
操作人員 | CREATOR,AUDITOR | |
數值 | LEVEL,AMOUNT,SCORE | |
長字元 | ADDRESS,COMPANY_NAME,SUMMARY,SUBJECT | |
不適合建索引的欄位 | 描述備註 | DESCRIPTION,REMARK,MEMO,DETAIL |
大欄位 | FILE_CONTENT,EMAIL_CONTENT |
如何知道SQL是否使用了正確的索引?
簡單SQL可以根據索引使用語法規則判斷,複雜的SQL不好辦,判斷SQL的響應時間是一種策略,但是這會受到資料量、主機負載及快取等因素的影響,有時資料全在快取裡,可能全表訪問的時間比索引訪問時間還少。要準確知道索引是否正確使用,需要到資料庫中檢視SQL真實的執行計劃,這個話題比較複雜,詳見SQL執行計劃專題介紹。
索引對DML(INSERT,UPDATE,DELETE)附加的開銷有多少?
這個沒有固定的比例,與每個表記錄的大小及索引欄位大小密切相關,以下是一個普通表測試資料,僅供參考:
索引對於Insert效能降低56%
索引對於Update效能降低47%
索引對於Delete效能降低29%
因此對於寫IO壓力比較大的系統,表的索引需要仔細評估必要性,另外索引也會佔用一定的儲存空間。
1.2、只通過索引訪問資料
有些時候,我們只是訪問表中的幾個欄位,並且欄位內容較少,我們可以為這幾個欄位單獨建立一個組合索引,這樣就可以直接只通過訪問索引就能得到資料,一般索引佔用的磁碟空間比表小很多,所以這種方式可以大大減少磁碟IO開銷。
如:select id,name from company where type='2';
如果這個SQL經常使用,我們可以在type,id,name上建立組合索引
create index my_comb_index on company(type,id,name);
有了這個組合索引後,SQL就可以直接通過my_comb_index索引返回資料,不需要訪問company表。
還是拿字典舉例:有一個需求,需要查詢一本漢語字典中所有漢字的個數,如果我們的字典沒有目錄索引,那我們只能從字典內容裡一個一個字計數,最後返回結果。如果我們有一個拼音目錄,那就可以只訪問拼音目錄的漢字進行計數。如果一本字典有1000頁,拼音目錄有20頁,那我們的資料訪問成本相當於全表訪問的50分之一。
切記,效能優化是無止境的,當效能可以滿足需求時即可,不要過度優化。在實際資料庫中我們不可能把每個SQL請求的欄位都建在索引裡,所以這種只通過索引訪問資料的方法一般只用於核心應用,也就是那種對核心表訪問量最高且查詢欄位資料量很少的查詢。
1.3、優化SQL執行計劃
SQL執行計劃是關係型資料庫最核心的技術之一,它表示SQL執行時的資料訪問演算法。由於業務需求越來越複雜,表資料量也越來越大,程式設計師越來越懶惰,SQL也需要支援非常複雜的業務邏輯,但SQL的效能還需要提高,因此,優秀的關係型資料庫除了需要支援複雜的SQL語法及更多函式外,還需要有一套優秀的演算法庫來提高SQL效能。
目前ORACLE有SQL執行計劃的演算法約300種,而且一直在增加,所以SQL執行計劃是一個非常複雜的課題,一個普通DBA能掌握50種就很不錯了,就算是資深DBA也不可能把每個執行計劃的演算法描述清楚。雖然有這麼多種演算法,但並不表示我們無法優化執行計劃,因為我們常用的SQL執行計劃演算法也就十幾個,如果一個程式設計師能把這十幾個演算法搞清楚,那就掌握了80%的SQL執行計劃調優知識。
由於篇幅的原因,SQL執行計劃需要專題介紹,在這裡就不多說了。
2、返回更少的資料
2.1、資料分頁處理
一般資料分頁方式有:
2.1.1、客戶端(應用程式或瀏覽器)分頁
將資料從應用伺服器全部下載到本地應用程式或瀏覽器,在應用程式或瀏覽器內部通過原生代碼進行分頁處理
優點:編碼簡單,減少客戶端與應用伺服器網路互動次數
缺點:首次互動時間長,佔用客戶端記憶體
適應場景:客戶端與應用伺服器網路延時較大,但要求後續操作流暢,如手機GPRS,超遠端訪問(跨國)等等。
2.1.2、應用伺服器分頁
將資料從資料庫伺服器全部下載到應用伺服器,在應用伺服器內部再進行資料篩選。以下是一個應用伺服器端Java程式分頁的示例:
List list=executeQuery(“select * from employee order by id”);
Int count= list.size();
List subList= list.subList(10, 20);
優點:編碼簡單,只需要一次SQL互動,總資料與分頁資料差不多時效能較好。
缺點:總資料量較多時效能較差。
適應場景:資料庫系統不支援分頁處理,資料量較小並且可控。
2.1.3、資料庫SQL分頁
採用資料庫SQL分頁需要兩次SQL完成
一個SQL計算總數量
一個SQL返回分頁後的資料
優點:效能好
缺點:編碼複雜,各種資料庫語法不同,需要兩次SQL互動。
oracle資料庫一般採用rownum來進行分頁,常用分頁語法有如下兩種:
直接通過rownum分頁:
select * from (
select a.*,rownum rn from
(select * from product a where company_id=? order by status) a
where rownum<=20)
where rn>10;
資料訪問開銷=索引IO+索引全部記錄結果對應的表資料IO
採用rowid分頁語法
優化原理是通過純索引找出分頁記錄的ROWID,再通過ROWID回表返回資料,要求內層查詢和排序欄位全在索引裡。
create index myindex on product(company_id,status);
select b.* from (
select * from (
select a.*,rownum rn from
(select rowid rid,status from product a where company_id=? order by status) a
where rownum<=20)
where rn>10) a, product b
where a.rid=b.rowid;
資料訪問開銷=索引IO+索引分頁結果對應的表資料IO
例項:
一個公司產品有1000條記錄,要分頁取其中20個產品,假設訪問公司索引需要50個IO,2條記錄需要1個表資料IO。
那麼按第一種ROWNUM分頁寫法,需要550(50+1000/2)個IO,按第二種ROWID分頁寫法,只需要60個IO(50+20/2);
2.2、只返回需要的欄位
通過去除不必要的返回欄位可以提高效能,例:
調整前:select * from product where company_id=?;
調整後:select id,name from product where company_id=?;
優點:
1、減少資料在網路上傳輸開銷
2、減少伺服器資料處理開銷
3、減少客戶端記憶體佔用
4、欄位變更時提前發現問題,減少程式BUG
5、如果訪問的所有欄位剛好在一個索引裡面,則可以使用純索引訪問提高效能。
缺點:增加編碼工作量
由於會增加一些編碼工作量,所以一般需求通過開發規範來要求程式設計師這麼做,否則等專案上線後再整改工作量更大。
如果你的查詢表中有大欄位或內容較多的欄位,如備註資訊、檔案內容等等,那在查詢表時一定要注意這方面的問題,否則可能會帶來嚴重的效能問題。如果表經常要查詢並且請求大內容欄位的概率很低,我們可以採用分表處理,將一個大表分拆成兩個一對一的關係表,將不常用的大內容欄位放在一張單獨的表中。如一張儲存上傳檔案的表:
T_FILE(ID,FILE_NAME,FILE_SIZE,FILE_TYPE,FILE_CONTENT)
我們可以分拆成兩張一對一的關係表:
T_FILE(ID,FILE_NAME,FILE_SIZE,FILE_TYPE)
T_FILECONTENT(ID, FILE_CONTENT)
通過這種分拆,可以大大提少T_FILE表的單條記錄及總大小,這樣在查詢T_FILE時效能會更好,當需要查詢FILE_CONTENT欄位內容時再訪問T_FILECONTENT表。
3、減少互動次數
3.1、batch DML
資料庫訪問框架一般都提供了批量提交的介面,jdbc支援batch的提交處理方法,當你一次性要往一個表中插入1000萬條資料時,如果採用普通的executeUpdate處理,那麼和伺服器互動次數為1000萬次,按每秒鐘可以向資料庫伺服器提交10000次估算,要完成所有工作需要1000秒。如果採用批量提交模式,1000條提交一次,那麼和伺服器互動次數為1萬次,互動次數大大減少。採用batch操作一般不會減少很多資料庫伺服器的物理IO,但是會大大減少客戶端與服務端的互動次數,從而減少了多次發起的網路延時開銷,同時也會降低資料庫的CPU開銷。
假設要向一個普通表插入1000萬資料,每條記錄大小為1K位元組,表上沒有任何索引,客戶端與資料庫伺服器網路是100Mbps,以下是根據現在一般計算機能力估算的各種batch大小效能對比值:
單位:ms | No batch | Batch=10 | Batch=100 | Batch=1000 | Batch=10000 |
伺服器事務處理時間 | 0.1 | 0.1 | 0.1 | 0.1 | 0.1 |
伺服器IO處理時間 | 0.02 | 0.2 | 2 | 20 | 200 |
網路交互發起時間 | 0.1 | 0.1 | 0.1 | 0.1 | 0.1 |
網路資料傳輸時間 | 0.01 | 0.1 | 1 | 10 | 100 |
小計 | 0.23 | 0.5 | 3.2 | 30.2 | 300.2 |
平均每條記錄處理時間 | 0.23 | 0.05 | 0.032 | 0.0302 | 0.03002 |
從上可以看出,Insert操作加大Batch可以對效能提高近8倍效能,一般根據主鍵的Update或Delete操作也可能提高2-3倍效能,但不如Insert明顯,因為Update及Delete操作可能有比較大的開銷在物理IO訪問。以上僅是理論計算值,實際情況需要根據具體環境測量。
3.2、In List
很多時候我們需要按一些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及記憶體成本,這個需要專業DBA評估。
3.3、設定Fetch Size
當我們採用select從資料庫查詢資料時,資料預設並不是一條一條返回給客戶端的,也不是一次全部返回客戶端的,而是根據客戶端fetch_size引數處理,每次只返回fetch_size條記錄,當客戶端遊標遍歷到尾部時再從服務端取資料,直到最後全部傳送完成。所以如果我們要從服務端一次取大量資料時,可以加大fetch_size,這樣可以減少結果資料傳輸的互動次數及伺服器資料準備時間,提高效能。
以下是jdbc測試的程式碼,採用本地資料庫,表快取在資料庫CACHE中,因此沒有網路連線及磁碟IO開銷,客戶端只遍歷遊標,不做任何處理,這樣更能體現fetch引數的影響:
String vsql ="select * from t_employee";
PreparedStatement pstmt = conn.prepareStatement(vsql,ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);
pstmt.setFetchSize(1000);
ResultSet rs = pstmt.executeQuery(vsql);
int cnt = rs.getMetaData().getColumnCount();
Object o;
while (rs.next()) {
for (int i = 1; i <= cnt; i++) {
o = rs.getObject(i);
}
}
測試示例中的employee表有100000條記錄,每條記錄平均長度135位元組
以下是測試結果,對每種fetchsize測試5次再取平均值:
fetchsize | elapse_time(s) |
1 | 20.516 |
2 | 11.34 |
4 | 6.894 |
8 | 4.65 |
16 | 3.584 |
32 | 2.865 |
64 | 2.656 |
128 | 2.44 |
256 | 2.765 |
512 | 3.075 |
1024 | 2.862 |
2048 | 2.722 |
4096 | 2.681 |
8192 | 2.715 |
Oracle jdbc fetchsize預設值為10,由上測試可以看出fetchsize對效能影響還是比較大的,但是當fetchsize大於100時就基本上沒有影響了。fetchsize並不會存在一個最優的固定值,因為整體效能與記錄集大小及硬體平臺有關。根據測試結果建議當一次性要取大量資料時這個值設定為100左右,不要小於40。注意,fetchsize不能設定太大,如果一次取出的資料大於JVM的記憶體會導致記憶體溢位,所以建議不要超過1000,太大了也沒什麼效能提高,反而可能會增加記憶體溢位的危險。
注:圖中fetchsize在128以後會有一些小的波動,這並不是測試誤差,而是由於resultset填充到具體對像時間不同的原因,由於resultset已經到本地記憶體裡了,所以估計是由於CPU的L1,L2 Cache命中率變化造成,由於變化不大,所以筆者也未深入分析原因。
iBatis的SqlMapping配置檔案可以對每個SQL語句指定fetchsize大小,如下所示:
<select id="getAllProduct" resultMap="HashMap" fetchSize="1000">
select * from employee
</select>
3.4、使用儲存過程
大型資料庫一般都支援儲存過程,合理的利用儲存過程也可以提高系統性能。如你有一個業務需要將A表的資料做一些加工然後更新到B表中,但是又不可能一條SQL完成,這時你需要如下3步操作:
a:將A表資料全部取出到客戶端;
b:計算出要更新的資料;
c:將計算結果更新到B表。
如果採用儲存過程你可以將整個業務邏輯封裝在儲存過程裡,然後在客戶端直接呼叫儲存過程處理,這樣可以減少網路互動的成本。
當然,儲存過程也並不是十全十美,儲存過程有以下缺點:
a、不可移植性,每種資料庫的內部程式設計語法都不太相同,當你的系統需要相容多種資料庫時最好不要用儲存過程。
b、學習成本高,DBA一般都擅長寫儲存過程,但並不是每個程式設計師都能寫好儲存過程,除非你的團隊有較多的開發人員熟悉寫儲存過程,否則後期系統維護會產生問題。
c、業務邏輯多處存在,採用儲存過程後也就意味著你的系統有一些業務邏輯不是在應用程式裡處理,這種架構會增加一些系統維護和除錯成本。
d、儲存過程和常用應用程式語言不一樣,它支援的函式及語法有可能不能滿足需求,有些邏輯就只能通過應用程式處理。
e、如果儲存過程中有複雜運算的話,會增加一些資料庫服務端的處理成本,對於集中式資料庫可能會導致系統可擴充套件性問題。
f、為了提高效能,資料庫會把儲存過程程式碼編譯成中間執行程式碼(類似於java的class檔案),所以更像靜態語言。當儲存過程引用的對像(表、檢視等等)結構改變後,儲存過程需要重新編譯才能生效,在24*7高併發應用場景,一般都是線上變更結構的,所以在變更的瞬間要同時編譯儲存過程,這可能會導致資料庫瞬間壓力上升引起故障(Oracle資料庫就存在這樣的問題)。
個人觀點:普通業務邏輯儘量不要使用儲存過程,定時性的ETL任務或報表統計函式可以根據團隊資源情況採用儲存過程處理。
3.5、優化業務邏輯
要通過優化業務邏輯來提高效能是比較困難的,這需要程式設計師對所訪問的資料及業務流程非常清楚。
舉一個案例:
某移動公司推出優惠套參,活動對像為VIP會員並且2010年1,2,3月平均話費20元以上的客戶。
那我們的檢測邏輯為:
select avg(money) as avg_money from bill where phone_no='13988888888' and date between '201001' and '201003';
select vip_flag from member where phone_no='13988888888';
if avg_money>20 and vip_flag=true then
begin
執行套參();
end;
如果我們修改業務邏輯為:
select avg(money) as avg_money from bill where phone_no='13988888888' and date between '201001' and '201003';
if avg_money>20 then
begin
select vip_flag from member where phone_no='13988888888';
if vip_flag=true then
begin
執行套參();
end;
end;
通過這樣可以減少一些判斷vip_flag的開銷,平均話費20元以下的使用者就不需要再檢測是否VIP了。
如果程式設計師分析業務,VIP會員比例為1%,平均話費20元以上的使用者比例為90%,那我們改成如下:
select vip_flag from member where phone_no='13988888888';
if vip_flag=true then
begin
select avg(money) as avg_money from bill where phone_no='13988888888' and date between '201001' and '201003';
if avg_money>20 then
begin
執行套參();
end;
end;
這樣就只有1%的VIP會員才會做檢測平均話費,最終大大減少了SQL的互動次數。
以上只是一個簡單的示例,實際的業務總是比這複雜得多,所以一般只是高階程式設計師更容易做出優化的邏輯,但是我們需要有這樣一種成本優化的意識。
3.6、使用ResultSet遊標處理記錄
現在大部分Java框架都是通過jdbc從資料庫取出資料,然後裝載到一個list裡再處理,list裡可能是業務Object,也可能是hashmap。
由於JVM記憶體一般都小於4G,所以不可能一次通過sql把大量資料裝載到list裡。為了完成功能,很多程式設計師喜歡採用分頁的方法處理,如一次從資料庫取1000條記錄,通過多次迴圈搞定,保證不會引起JVM Out of memory問題。
以下是實現此功能的程式碼示例,t_employee表有10萬條記錄,設定分頁大小為1000:
d1 = Calendar.getInstance().getTime();
vsql = "select count(*) cnt from t_employee";
pstmt = conn.prepareStatement(vsql);
ResultSet rs = pstmt.executeQuery();
相關推薦
mysql 和Oracle的資料庫詳解效能優化
出處:1.資料庫訪問優化法則要正確的優化SQL,我們需要快速定位能性的瓶頸點,也就是說快速找到我們SQL主要的開銷在哪裡?而大多數情況效能最慢的裝置會是瓶頸點,如下載時網路速度可能會是瓶頸點,本地複製檔案時硬碟可能會是瓶頸點,為什麼這些一般的工作我們能快速確認瓶頸點呢,因為我
windows下自動備份mysql和oracle資料庫
rem ******Oracle backup start******** @echo off forfiles /p "C:\DatabaseBackup\egov\essucap" /m essucap_backup_*.dmp -d -7
Quartz學習——SSMM(Spring+SpringMVC+Mybatis+Mysql)和Quartz整合詳解(四)
當任何時候覺你得難受了,其實你的大腦是在進化,當任何時候你覺得輕鬆,其實都在使用以前的壞習慣。 通過前面的學習,你可能大致瞭解了Quartz,本篇博文為你開啟學習SSMM+Quartz的旅程!歡迎上車,開始美好的旅程! 本篇是在SSM框架——Spri
Navicat for mysql遠端連線資料庫詳解(1130錯誤解決方法)
用Navicat for mysql連線資料庫測試下連線 如果出現1130錯誤錯誤程式碼是1130,ERROR 1130: Host xxx.xxx.xxx.xxx is not allowed to connect to this MySQL server論壇上有些朋友說
Java通過配置檔案連線Mysql和Oracle資料庫
配置檔案: db.properties #Mysql parameter mysqldriver=com.mysql.jdbc.Driver mysqlurl=jdbc:mysql://127.0.0.1:3306/database mysqluser=username
VC使用ADO連線Oracle資料庫詳解(含原始碼下載)
ADO 主要物件介紹 ADO物件包括:連線物件(Connection Object)、命令物件 (Command Object) 、記錄集對象(RecordSet Object)、欄位物件(Field Object) 、記錄物件(Record Object)
關於mybatis中對mysql和Oracle資料庫分頁外掛的使用
首先是Oracle資料庫:在mybatis相對應的mapper.xml檔案裡:<sql id="OracleDialectPrefix"> <!-- WARNIN
在tomcat中配置MySQL和oracle資料庫連線池的異同
一、在tomcat中配置MySql資料庫連線池 Java程式碼: public Connection conn = null; public Connection getConnection()throws ClassNotFoundException, S
mysql乾貨——資料庫字符集和校對規則詳解
一、什麼是字符集 字元是多個文字和符號的總稱,包括各個國家的文字、標點符號、圖形符號、數字等。字符集多個字元的集合。 字元集合種類較多,每個字符集包含的字元的個數不同。對於字符集不支援的字元,則以亂碼顯示。 常見的字符集有ASCII字符集、GBK字符集、GB2312字符集、GB18030字
SELECT INTO 和 INSERT INTO SELECT 兩種表複製語句詳解(SQL資料庫和Oracle資料庫的區別)
https://www.cnblogs.com/mq0036/p/4155136.html 我們經常會遇到需要表複製的情況,如將一個table1的資料的部分欄位複製到table2中,或者將整個table1複製到table2中,這時候我們就要使用SELECT INTO 和 INSER
Mysql索引詳解及優化(key和index區別)
MySQL索引的概念 索引是一種特殊的檔案(InnoDB資料表上的索引是表空間的一個組成部分),它們包含著對資料表裡所有記錄的引用指標。更通俗的說,資料庫索引好比是一本書前面的目錄,能加快資料庫的查詢速度。 索引分為聚簇索引和非聚簇索引兩種,聚簇索引是按照資料存放
Android進階——效能優化之佈局渲染原理和底層機制詳解(四)
引言 UI 全稱User Interaction,我第一次聽到這個名詞是在大學的時候,當時候上人機互動課,我們教授說他認為iPhone的i 就是代表Interaction的意思,暫且不必爭辯是非。回到我們軟體開發中來,UI是使用者感知與互動的第一且唯一的途徑,
MySQL配置文件mysql.ini參數詳解、MySQL性能優化
說明 select 磁盤 addition sock 硬盤 並發連接 查詢緩存 show my.ini(Linux系統下是my.cnf),當mysql服務器啟動時它會讀取這個文件,設置相關的運行環境參數。 my.ini分為兩塊:Client Section和Serv
MySQL存儲引擎中的MyISAM和InnoDB區別詳解
訪問 過程 包含 lte 處理機制 comm 用戶 isam log MyISAM是MySQL的默認數據庫引擎(5.5版之前),由早期的ISAM(Indexed Sequential Access Method:有索引的順序訪問方法)所改良。雖然性能極佳,但卻有一個缺點:不
mysql測試和sysbench工具詳解
無法 http six 多次 count 直接 log syntax git 前言 作為一名後臺開發,對數據庫進行基準測試,以掌握數據庫的性能情況是非常必要的。本文介紹了MySQL基準測試的基本概念,以及使用sysbench對MySQL進行基準測試的詳細方法。 文章有疏漏之
java程式設計師菜鳥進階(五)oracle基礎詳解(五)oracle資料庫體系架構詳解
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
javaweb:JDBC連線MYSQL資料庫詳解,使用JDBC對資料庫進行CRUD操作以及DAO模式的介紹
JDBC簡介: JDBC全稱為:Java DataBase Connectivity(java資料庫連線)。 SUN公司為了簡化、統一對資料庫的操作,定義了一套Java操作資料庫的規範,稱之為JDBC。 組成JDBC的2個包: 連結:https://pan
mysql篇第三課:庫的建立和表的詳解
這節課我們講講怎麼建庫,以及對錶的建立詳細分析一下: 建庫特別簡單: create database dbname; 來試試 接下來講建表,先把建表語句粘一下:
MySQL——簡單的安全管理、資料庫維護、效能優化
訪問控制 MySQL伺服器的安全基礎是:使用者應該對他們需要的資料具有適當的訪問許可權,既不能多也不能少,即使用者不能對過多的資料具有過多的訪問許可權。 1、對於非現實的資料庫實驗時可以使用root使用者進行登入,但是在現實世界的日常工作中,決不能使用root(必須嚴肅對待root登入的
MySQL資料庫詳解
1.什麼是資料庫? 資料庫是多個特俗檔案的集合,是用來儲存資料的,可高效能的儲存資料和管理資料 2.資料庫管理系統: 1.資料庫檔案 :用於儲存資料 2.資料庫管理系統服務端:用於管理資料庫的檔案