性能優化(Myqsql優化)

執行計劃

複習一下索引java

列無重複值,能夠建索引:惟一索引和普通索引 彙集索引和非彙集索引均可以是惟一的。所以,只要列中的數據是惟一的,就能夠在同一個表上建立一個惟一的彙集索引和多個惟一的非彙集索引。 建了索引性能獲得提升!mysql

須要說明: 惟一索引必定要當心,它帶有惟一約束。 須要說明2: 查詢區分度 SELECT COUNT(DISTINCT 列_xx)/COUNT(*) FROM 表正則表達式

存儲引擎及文件格式比較sql

建索引的目的數據庫

加快查詢速度,固然了,使用索引後查詢有跡可循。 減小I/O操做,經過索引的路徑來檢索數據,不是在磁盤中隨機檢索。 消除磁盤排序,索引是排序的,走完索引就排序完成併發

什麼時候使用索引函數

查詢返回的記錄數性能

排序表<40%大數據

非排序表 <7%優化

表的碎片較多(頻繁增長、刪除)

基礎表維護時,系統要同時維護索引,不合理的索引將嚴重影響系統資源,主要表如今CPU和I/O上;

插入、更新、刪除數據產生大量db file sequential read鎖等待;

 

1.頻繁更新的字段不適合創建索引

2.where條件中用不到的字段不適合創建索引

3.表數據能夠肯定比較少的不須要建索引

4.數據重複且發佈比較均勻的的字段不適合建索引(惟一性太差的字段不適合創建索引),例如性別,真假值

5. 參與列計算的列不適合建索引

執行計劃

預備知識-事務

ACID

原子性:一個事務(transaction)中的全部操做,要麼所有完成,要麼所有不完成,不會結束在中間某個環節。事務在執行過程當中發生錯誤,會被恢復(Rollback)到事務開始前的狀態,就像這個事務歷來沒有執行過同樣。

一致性:在事務開始以前和事務結束之後,數據庫的完整性沒有被破壞。這表示寫入的資料必須徹底符合全部的預設規則,這包含資料的精確度、串聯性以及後續數據庫能夠自發性地完成預約的工做。

隔離性:數據庫容許多個併發事務同時對其數據進行讀寫和修改的能力,隔離性能夠防止多個事務併發執行時因爲交叉執行而致使數據的不一致。事務隔離分爲不一樣級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和串行化(Serializable)。

持久性:事務處理結束後,對數據的修改就是永久的,即使系統故障也不會丟失。

 

預備知識-鎖

1.按照對數據操做的類型分   

讀鎖:也稱爲共享鎖,針對同一資源,多個讀操做是能夠並行進行的,而且互不影響。     

寫鎖:也稱排它鎖。 當前線程寫數據的時候,會阻斷其餘線程來讀數據和寫數據

2.按照 粒度來分       

表鎖:就是鎖整個表(myisam)       

行鎖:就是鎖單獨某個表中的某一行(innodb)       

葉鎖:他是鑑於表鎖和行數之間的一種粒度

Explain

1.Id,SQL執行的順利的標識,SQL從大到小的執行.

2. select_type,就是select類型,能夠有如下幾種

3.Table,顯示這一行的數據是關於哪張表的.

4.Type,這列很重要,顯示了鏈接使用了哪一種類別,有無使用索引. 從最好到最差的鏈接類型爲const、eq_reg、ref、range、indexhe和ALL

5.possible_keys,possible_keys列指出MySQL能使用哪一個索引在該表中找到行。

6. Key,key列顯示MySQL實際決定使用的鍵(索引)。

7.key_len,使用的索引的長度。在不損失精確性的狀況下,長度越短越好

8. Ref,ref列顯示使用哪一個列或常數與key一塊兒從表中選擇行。

9. Rows,rows列顯示MySQL認爲它執行查詢時必須檢查的行數。

10. Extra,該列包含MySQL解決查詢的詳細信息,下面詳細.

select_type

一、SIMPLE,簡單查詢 
二、PRIMARY,主查詢(多個表關聯時) 
三、UNION,聯合查詢 
四、DEPENDENT UNION,子查詢中的聯合查詢 
五、UNION RESULT,聯合的結果集 
六、SUBQUERY,第一個子查詢 
七、 DEPENDENT SUBQUERY,子查詢中第一句 
八、DERIVED,派生表

type
一、system, const聯接類型的一個特例。表僅有一行知足條件
二、const,表最多有一個匹配行,它將在查詢開始時被讀取。由於僅有一行,在這行的列值可被優化器剩餘部分認爲是常數。const表很快,由於它們只讀取一次!
三、eq_ref,對於每一個來自於前面的表的行組合,從該表中讀取一行。這多是最好的聯接類型,除了const類型。它用在一個索引的全部部分被聯接使用而且索引是UNIQUE或PRIMARY KEY。 eq_ref能夠用於使用= 操做符比較的帶索引的列。比較值能夠爲常量或一個使用在該表前面所讀取的表的列的表達式。
四、.ref,對於每一個來自於前面的表的行組合,全部有匹配索引值的行將從這張表中讀取。若是聯接只使用鍵的最左邊的前綴,或若是鍵不是UNIQUE或PRIMARY KEY(換句話說,若是聯接不能基於關鍵字選擇單個行的話),則使用ref。若是使用的鍵僅僅匹配少許行,該聯接類型是不錯的。 ref能夠用於使用=或<=>操做符的帶索引的列。
五、 ref_or_null,該聯接類型如同ref,可是添加了MySQL能夠專門搜索包含NULL值的行。在解決子查詢中常用該聯接類型的優化。 六、index_merge,該聯接類型表示使用了索引合併優化方法。在這種狀況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
七、unique_subquery,該類型替換了下面形式的IN子查詢的ref。value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,能夠徹底替換子查詢,效率更高。
八、index_subquery,該聯接類型相似於unique_subquery。能夠替換IN子查詢
九、range、只檢索給定範圍的行,使用一個索引來選擇行。key列顯示使用了哪一個索引。key_len包含所使用索引的最長關鍵元素。在該類型中ref列爲NULL。
十、index、該聯接類型與ALL相同,除了只有索引樹被掃描。這一般比ALL快,由於索引文件一般比數據文件小。
十一、ALL,對於每一個來自於先前的表的行組合,進行完整的表掃描。若是表是第一個沒標記const的表,這一般很差,而且一般在它狀況下不好。一般能夠增長更多的索引而不要使用ALL,使得行能基於前面的表中的常數值或列值被檢索出。

Extra  這個列能夠顯示的信息很是多,有幾十種。經常使用以下:
(1).Distinct, 一旦MYSQL找到了與行相聯合匹配的行,就再也不搜索了
(2).Not exists ,使用了反鏈接,先查詢外表,再查詢內表
(3).Range checked for each Record(index map:#) 沒有找到理想的索引,所以對於從前面表中來的每個行組合,MYSQL檢查使用哪一個索引,並用它來從表中返回行。這是使用索引的最慢的鏈接之一 
(4).Using filesort 看到這個的時候,查詢須要優化。MYSQL須要進行額外的步驟來發現如何對返回的行排序。它根據鏈接類型以及存儲排序鍵值和匹配條件的所有行的行指針來排序所有行 
(5).Using index 列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對錶的所有的請求列都是同一個索引的部分的時候 
(6).Using temporary 看到這個的時候,查詢須要優化。這裏,MYSQL須要建立一個臨時表來存儲結果,這一般發生在對不一樣的列集進行ORDER BY上,而不是GROUP BY上 
(7).Using where 使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。若是不想返回表中的所有行,而且鏈接類型ALL或index,這就會發生,或者是查詢有問題
(8).firstmatch(tb_name):5.6.x開始引入的優化子查詢的新特性之一,常見於where字句含有in()類型的子查詢。若是內表的數據量比較大,就可能出現這個.
(9).loosescan(m..n):5.6.x以後引入的優化子查詢的新特性之一,在in()類型的子查詢中,子查詢返回的可能有重複記錄時,就可能出現這個

MySQL執行計劃的侷限

•EXPLAIN不會告訴你關於觸發器、存儲過程的信息或用戶自定義函數對查詢的影響狀況
•EXPLAIN不考慮各類Cache
•EXPLAIN不能顯示MySQL在執行查詢時所做的優化工做
•部分統計信息是估算的,並不是精確值
•EXPALIN只能解釋SELECT操做,其餘操做要重寫爲SELECT後查看執行計劃

幾個場景

分頁特殊處理

Select * from fentrust e Inner join (select fid from fentrust limit 4100000, 10) a on a.fid = e.fid

Select * from fentrust e limit 4100000, 10

Select * from fentrust e where fid in(select fid from (select fid from fentrust limit 4100000, 10) a )

原理 索引覆蓋最快

善用子查詢

原理 子查詢比join快,雖然規律不絕對,但對大表多數有效

Where條件順序

SELECT * FROM `fentrustlog` e WHERE e.fcount > 1000 and e.famount > 300000

e.fcount > 1000:48萬行

e.famount > 300000: 24行

誰先誰後? 結果是不太有效

大事務問題

儘可能避免大事務操做,提升系統併發能力。 有時沒法避免,改用定時器延遲處理

不走索引的狀況

SELECT ` famount ` FROM ` fentrust ` WHERE ` famount `+10=30;-- 不會使用索引,由於全部索引列參與了計算

SELECT `famount` FROM `fentrust` WHERE LEFT(`fcreateTime`,4) <1990; -- 不會使用索引,由於使用了函數運算,原理與上面相同

SELECT * FROM ` fuser` WHERE `floginname` LIKE‘138%' -- 走索引

SELECT * FROM ` fuser ` WHERE ` floginname ` LIKE "%7488%" -- 不走索引 -- 正則表達式不使用索引,這應該很好理解,因此爲何在SQL中很難看到regexp關鍵字的緣由 -- 字符串與數字比較不使用索引;

EXPLAIN SELECT * FROM `a` WHERE `a`=1 -- 不走索引

select * from fuser where floginname='xxx' or femail='xx' or fstatus=1 --若是條件中有or,即便其中有條件帶索引也不會使用。換言之,就是要求使用的全部字段,都必須創建索引, 咱們建議你們儘可能避免使用or 關鍵字

若是mysql估計使用全表掃描要比使用索引快,則不使用索引

千萬級數據表優化

大數據表優化

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

2.應儘可能避免在 where 子句中對字段進行 null 值判斷,不然將致使引擎放棄使用索引而進行全表掃描,如:select id from t where num is null能夠在num上設置默認值0,確保表中num列沒有null值,而後這樣查詢:select id from t where num=0

3.應儘可能避免在 where 子句中使用!=或<>操做符,不然引擎將放棄使用索引而進行全表掃描。

4.應儘可能避免在 where 子句中使用or 來鏈接條件,不然將致使引擎放棄使用索引而進行全表掃描,如:select id from t where num=10 or num=20能夠這樣查詢:select id from t where num=10 union all select id from t where num=20

5.in 和 not in 也要慎用,不然會致使全表掃描,如:select id from t where num in(1,2,3) 對於連續的數值,能用 between 就不要用 in 了:select id from t where num between 1 and 3

6.下面的查詢也將致使全表掃描:select id from t where name like '李%'若要提升效率,能夠考慮全文檢索。

7. 若是在 where 子句中使用參數,也會致使全表掃描。由於SQL只有在運行時纔會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然 而,若是在編譯時創建訪問計劃,變量的值仍是未知的,於是沒法做爲索引選擇的輸入項。以下面語句將進行全表掃描:select id from t where num=@num能夠改成強制查詢使用索引:select id from t with(index(索引名)) where num=@num

8.應儘可能避免在 where 子句中對字段進行表達式操做,這將致使引擎放棄使用索引而進行全表掃描。如:select id from t where num/2=100應改成:select id from t where num=100*2

 9.應儘可能避免在where子句中對字段進行函數操做,這將致使引擎放棄使用索引而進行全表掃描。如:select id from t where substring(name,1,3)='abc' ,name以abc開頭的id 應改成: select id from t where name like 'abc%'

10.不要在 where 子句中的「=」左邊進行函數、算術運算或其餘表達式運算,不然系統將可能沒法正確使用索引。

11.在使用索引字段做爲條件時,若是該索引是複合索引,那麼必須使用到該索引中的第一個字段做爲條件時才能保證系統使用該索引,不然該索引將不會被使用,而且應儘量的讓字段順序與索引順序相一致。

12.不要寫一些沒有意義的查詢,如須要生成一個空表結構:select col1,col2 into #t from t where 1=0 這類代碼不會返回任何結果集,可是會消耗系統資源的,應改爲這樣: create table #t(...)

13.不少時候用 exists 代替 in 是一個好的選擇:select num from a where num in(select num from b) 用下面的語句替換: select num from a where exists(select 1 from b where num=a.num)

14.並非全部索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重複時,SQL查詢可能不會去利用索引,如一表中有字段sex,male、female幾乎各一半,那麼即便在sex上建了索引也對查詢效率起不了做用。

15. 索引並非越多越好,索引當然可 以提升相應的 select 的效率,但同時也下降了 insert 及 update 的效率,由於 insert 或 update 時有可能會重建索引,因此怎樣建索引須要慎重考慮,視具體狀況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有 必要。 

16. 應儘量的避免更新 clustered 索引數據列,由於 clustered 索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將致使整個表記錄的順序的調整,會耗費至關大的資源。若應用系統須要頻繁更新 clustered 索引數據列,那麼須要考慮是否應將該索引建爲 clustered 索引。

17.儘可能使用數字型字段,若只含數值信息的字段儘可能不要設計爲字符型,這會下降查詢和鏈接的性能,並會增長存儲開銷。這是由於引擎在處理查詢和鏈接時會逐個比較字符串中每個字符,而對於數字型而言只須要比較一次就夠了。

18.儘量的使用 varchar/nvarchar 代替 char/nchar ,由於首先變長字段存儲空間小,能夠節省存儲空間,其次對於查詢來講,在一個相對較小的字段內搜索效率顯然要高些。

19.任何地方都不要使用 select * from t ,用具體的字段列表代替「*」,不要返回用不到的任何字段。

20.儘可能使用表變量來代替臨時表。若是表變量包含大量數據,請注意索引很是有限(只有主鍵索引)。

21.避免頻繁建立和刪除臨時表,以減小系統表資源的消耗。

22.臨時表並非不可以使用,適當地使用它們可使某些例程更有效,例如,當須要重複引用大型表或經常使用表中的某個數據集時。可是,對於一次性事件,最好使用導出表。 

23.在新建臨時表時,若是一次性插入數據量很大,那麼可使用 select into 代替 create table,避免形成大量 log ,以提升速度;若是數據量不大,爲了緩和系統表的資源,應先create table,而後insert。

24.若是使用到了臨時表,在存儲過程的最後務必將全部的臨時表顯式刪除,先 truncate table ,而後 drop table ,這樣能夠避免系統表的較長時間鎖定。 25.儘可能避免使用遊標,由於遊標的效率較差,若是遊標操做的數據超過1萬行,那麼就應該考慮改寫。

26.使用基於遊標的方法或臨時表方法以前,應先尋找基於集的解決方案來解決問題,基於集的方法一般更有效。

27. 與臨時表同樣,遊標並非不可以使 用。對小型數據集使用 FAST_FORWARD 遊標一般要優於其餘逐行處理方法,尤爲是在必須引用幾個表才能得到所需的數據時。在結果集中包括「合計」的例程一般要比使用遊標執行的速度快。若是開發時 間容許,基於遊標的方法和基於集的方法均可以嘗試一下,看哪種方法的效果更好。

28.在全部的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每一個語句後向客戶端發送DONE_IN_PROC 消息。

29.儘可能避免大事務操做,提升系統併發能力。

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

批量刪除,而不一次性

while(true){
   //每次只作1000條
   「delete from logs where log_date <= ’2012-11-01’ limit 1000」;
   if(mysql_affected_rows == 0){
     //刪除完成,退出!
     break;
   }
    //每次暫停一段時間,釋放表讓其餘進程/線程訪問。
    Thread.sleep(5000L)

}

大數據表優化

創建彙總表

創建流水錶

分表分庫

相關文章
相關標籤/搜索