MySQL優化一

MySQL優化

前言

從程序員角度談數據庫性能的優化

開發人員:如果你是做數據庫開發,那本文的內容非常適合,因爲本文是從程序員的角度來談數據庫性能優化。

架構師:如果你已經是數據庫應用的架構師,那本文的知識你應該清楚90%,否則你可能是一個喜歡折騰的架構師。

DBA(數據庫管理員):大型數據庫優化的知識非常複雜,本文只是從程序員的角度來談性能優化,DBA除了需要了解這些知識外,還需要深入數據庫的內部體系架構來解決問題。

 主要是優化數據訪問層:

(1)一方面是側重數據庫原理,例如創建索引等

(2)一方面從SQL語句優化來提高數據查詢效率

一、RowidRownum

Rowid和Rownum對於數據庫開發人員來說基本很少用到,因爲在企業數據庫開發中大多都是進行數據批處理,但是對於其他數據庫人員來說還是會用到的。

rowid和rownum都是虛列,但含義完全不同。rowid是物理地址,用於定位oracle中具體數據的物理存儲位置,而rownum則是sql的輸出結果排序。通俗的講:rowid是相對不變的,rownum會變化,尤其是使用order by的時候。

rowid 用於定位數據表中某條數據的位置,是唯一的、也不會改變

rownum 表示查詢某條記錄在整個結果集中的位置, 同一條記錄查詢條件不同對應的 rownum 是不同的而 rowid 是不會變的

二、MySQL數據庫的優化

數據庫的優化分爲三大類:

CPU及內存:緩存數據訪問、比較、排序、事務檢測、SQL解析、函數或邏輯運算;

網絡:結果數據傳輸、SQL請求、遠程數據庫訪問(dblink);

硬盤:數據訪問、數據寫入、日誌記錄、大數據量排序、大表連接。

影響數據傳輸的因素主要爲延遲和帶寬:效率排序:

cup的處理>網絡傳輸數據>訪問磁盤

顯然,在訪問磁盤時效率最低。

所以,優化數據庫,主要是對數據訪問的優化,即減少訪問的數據。

一、減少數據訪問

創建索引:減少數據的訪問

索引:索引是一種特殊的文件(InnoDB數據表上的索引是表空間的一個組成部分),它們包含着對數據表裏所有記錄的引用指針。更通俗的說,數據庫索引好比是一本書前面的目錄,能加快數據庫的查詢速度。在沒有索引的情況下,數據庫會遍歷全部數據後選擇符合條件的;而有了相應的索引之後,數據庫會直接在索引中查找符合條件的選項。(注:一般數據庫默認都會爲主鍵生成索引)。

PS:索引分爲聚簇索引和非聚簇索引兩種,聚簇索引是按照數據存放的物理位置爲順序的,而非聚簇索引就不一樣了;聚簇索引能提高多行檢索的速度,而非聚簇索引對於單行的檢索很快。

 

 

1、索引的分類:

邏輯上:普通索引、唯一索引、單列索引、多列索引、組合索引(最左前綴)

物理上:B-tree索引、Full-text索引(全文索引)、R-tree索引。

一個表中可以建多個索引,就如一本字典可以建多個目錄一樣(按拼音、筆劃、部首等等)。

一個索引也可以由多個字段組成,稱爲組合索引,如上圖就是一個按部首+筆劃的組合目錄。

2、什麼字段上創建索引

(1)語句執行頻率高,一天會有幾千次以上;

(2)作爲查詢條件的字段。

(3)通過字段條件可篩選的記錄集很小。

(4)描述備註、大字段不適合創建索引。

3、不適合創建索引的情況

(1)簡單SQL可以根據索引使用語法規則判斷,複雜的SQL不好辦,判斷SQL的響應時間是一種策略,但是這會受到數據量、主機負載及緩存等因素的影響,有時數據全在緩存裏,可能全表訪問的時間比索引訪問時間還少。要準確知道索引是否正確使用,需要到數據庫中查看SQL真實的執行計劃;

(2)索引也是佔用存儲空間的,此外,索引對DML(insert、update、delete)語句的性能也有影響。

4、不用索引的情況

(1)應儘量避免在 where 子句中使用 != 或 <> 操作符,否則將導致引擎放棄使用索引而進行全表掃描。

(2)應儘量避免在 where 子句中使用 or 來連接條件,如果一個字段有索引,一個字段沒有索引,將導致引擎放棄使用索引而進行全表掃描,如:

select id from twhere num=10 or Name = 'admin'

可以這樣查詢:

select id from twhere num = 10

union all

select id from twhere Name = 'admin'。

5、索引可不能亂建!!!

我記得去年幫同事整理一個大表的數據,從中獲取6000萬的數據,插入到新表中,沒索引時,3小時插入完成,只建了一個索引,9個多小時完成。

6、

SQL語句優化:減少數據的訪問

1、對查詢進行優化,要儘量避免全表掃描,首先應考慮在 where order by 涉及的列上建立索引。

2、注意SQL語句的優化,減少全表掃描,如:

(1)下面的查詢也將導致全表掃描:

select id from twhere name like ‘%abc%’

若要提高效率,可以考慮全文檢索。

(2)儘量不用*,需要什麼字段,就查詢什麼字段。

3、表字段的選擇

(1)整型>data,time>enum,char,varchar>blob;整數類型的列字段運算快,節省空間。

(2)大的字段浪費內存,影響速度,如:以varchar(10),varchar(300)存儲的內容相同,但在聯查時varchar(300)要花更多內存。

(3)減少null的使用,佔用的磁盤空間大。

(4)減少數據庫中列對null的使用,儘量使用not null。

(5)儘可能的使用 varchar/nvarchar 代替 char/nchar ,因爲首先變長字段存儲空間小,可以節省存儲空間,其次對於查詢來說,在一個相對較小的字段內搜索效率顯然要高些。

4、儘量減少可以避免的日誌

(1)刪除表中所有數據時,用TRUNCATE,DELETE 語句每次刪除一行,並在事務日誌中爲所刪除的每行記錄一項。TRUNCATE TABLE 通過釋放用於存儲表數據的數據頁來刪除數據,並且在事務日誌中只記錄頁釋放,使用的鎖通常較少。

(2)Update 語句,如果只更改1、2個字段,不要Update全部字段,否則頻繁調用會引起明顯的性能消耗,同時帶來大量日誌。

(3)在新建臨時表時,如果一次性插入數據量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,爲了緩和系統表的資源,應先create table,然後insert。

5、儘量避免大事務操作,提高系統併發能力。

6、儘量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。

二、減少返回數據

1、分頁

2、只返回需要的字段

三、減少交互次數

[1]批量提交batch

[2]批量返回:設置fetch size屬性,增加服務器向客戶端的每次請求的返回數據量

[3]根據ID查詢時使用in

[4]使用存儲過程

[5]優化業務邏輯

(1)batch(批量)提交數據,減少客戶端與服務端的交互次數。

一般數據庫都會提供批量提交接口,採用batch操作一般不會減少很多數據庫服務器的物理IO,但是會大大減少客戶端與服務端的交互次數,從而減少了多次發起的網絡延時開銷,同時也會降低數據庫的CPU開銷。

2)使用 In List

即我們會經常根據id進行查詢數據,可以寫一個SQL語句:

for :var in ids[] do begin

  select * frommytable where id=:var;

end;

但是可以做一個優化,即用idINLIST的形式來寫。

select * from mytable where id in(:id1,id2,...,idn);

這樣可以大大減少對數據庫發起SQL的請求數,從而提高性能。但是in中的id數並非是可以無限放的。

【1】數據庫本身有限制;

【2】數據庫的基於成本的優化規則,可能改變SQL執行計劃,由索引變爲全表掃描,佔用內存會變大。

首先大部份數據庫都會有SQL長度和IN裏個數的限制,如ORACLEIN裏就不允許超過1000個值。

另外當前數據庫一般都是採用基於成本的優化規則,當IN數量達到一定值時有可能改變SQL執行計劃,從索引訪問變成全表訪問,這將使性能急劇變化。隨着SQLIN的裏面的值個數增加,SQL的執行計劃會更復雜,佔用的內存將會變大,這將會增加服務器CPU及內存成本。評估在IN裏面一次放多少個值還需要考慮應用服務器本地內存的開銷,有併發訪問時要計算本地數據使用週期內的併發上限,否則可能會導致內存溢出。

綜合考慮,一般IN裏面的值個數超過20個以後性能基本沒什麼太大變化,也特別說明不要超過100,超過後可能會引起執行計劃的不穩定性及增加數據庫CPU及內存成本,這個需要專業DBA評估。

3)設置Fetch Size

1】由數據庫返回客戶端時,fetch size屬性在數據訪問層框架可以設置

2】當返回數據量較大時,一般設爲100

3fetchsize並不會存在一個最優的固定值,因爲整體性能與記錄集大小及硬件平臺有關

4etchsize不能設置太大,如果一次取出的數據大於JVM的內存會導致內存溢出,所以建議不要超過1000,太大了也沒什麼性能提高,反而可能會增加內存溢出的危險。

當我們採用select從數據庫查詢數據時,數據默認並不是一條一條返回給客戶端的,也不是一次全部返回客戶端的,而是根據客戶端fetch_size參數處理,每次只返回fetch_size條記錄,當客戶端遊標遍歷到尾部時再從服務端取數據,直到最後全部傳送完成。所以如果我們要從服務端一次取大量數據時,可以加大fetch_size,這樣可以減少結果數據傳輸的交互次數及服務器數據準備時間,提高性能。

(1)使用存儲過程

(2)優化業務邏輯

(3)使用Resultset遊標處理記錄

四、減少數據庫服務器CPU運算

1)使用綁定變量

綁定變量是指SQL中對變化的值採用變量參數的形式提交,而不是在SQL中直接拼寫對應的值。

非綁定變量寫法:Select * fromemployee where id=1234567

綁定變量寫法:

Select *from employee where id=?

Preparestatement.setInt(1,1234567)

JavaPreparestatement就是爲處理綁定變量提供的對像,綁定變量有以下優點:

1、防止SQL注入

2、提高SQL可讀性

3、提高SQL解析性能,不使用綁定變更我們一般稱爲硬解析,使用綁定變量我們稱爲軟解析。

2)合理使用排序

3)減少比較操作

4)大量複雜運算在客戶端處理

五、利用更多的資源

(1)客戶端多進程並行訪問

(2數據庫並行處理

 

 

                                                               


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章