你好,你有一份MySQL性能管理及架構設計指南待領取

1、什麼影響了數據庫查詢速度前端

一、影響數據庫查詢速度的四個因素mysql




二、風險分析程序員

QPS:Queries Per Second意思是「每秒查詢率」,是一臺服務器每秒可以相應的查詢次數,是對一個特定的查詢服務器在規定時間內所處理流量多少的衡量標準。sql

TPS:是TransactionsPerSecond的縮寫,也就是事務數/秒。它是軟件測試結果的測量單位。客戶機在發送請求時開始計時,收到服務器響應後結束計時,以此來計算使用的時間和完成的事務個數。數據庫

Tips:最好不要在主庫上數據庫備份,大型活動前取消這樣的計劃。緩存


  • 效率低下的SQL:超高的QPS與TPS。
  • 大量的併發:數據鏈接數被佔滿(max_connection默認100,通常把鏈接數設置得大一些)。
  • 併發量:同一時刻數據庫服務器處理的請求數量
  • 超高的CPU使用率:CPU資源耗盡出現宕機。
  • 磁盤IO:磁盤IO性能忽然降低、大量消耗磁盤性能的計劃任務。解決:更快磁盤設備、調整計劃任務、作好磁盤維護。


三、網卡流量:如何避免沒法鏈接數據庫的狀況安全

  • 減小從服務器的數量(從服務器會從主服務器複製日誌)
  • 進行分級緩存(避免前端大量緩存失效)
  • 避免使用select * 進行查詢
  • 分離業務網絡和服務器網絡


四、大表帶來的問題性能優化

1)大表的特色服務器

  • 記錄行數巨大,單表超千萬
  • 表數據文件巨大,超過10個G


2)大表的危害網絡

①慢查詢:很難在短期內過濾出須要的數據

查詢字區分度低 -> 要在大數據量的表中篩選出來其中一部分數據會產生大量的磁盤io -> 下降磁盤效率


②對DDL影響:


創建索引須要很長時間:

  • MySQL -v<5.5 創建索引會鎖表
  • MySQL -v>=5.5 創建索引會形成主從延遲(mysql創建索引,先在組上執行,再在庫上執行)


修改表結構須要長時間的鎖表:會形成長時間的主從延遲('480秒延遲')


3)如何處理數據庫上的大表

分庫分表把一張大表分紅多個小表。

難點:


  • 分表主鍵的選擇
  • 分表後跨分區數據的查詢和統計


五、大事務帶來的問題

1) 什麼是事務




2)事務的ACID屬性

①原子性(atomicity):所有成功,所有回滾失敗。銀行存取款。

②一致性(consistent):銀行轉帳的總金額不變。

③隔離性(isolation):

隔離性等級:


  • 未提交讀(READ UNCOMMITED) 髒讀,兩個事務之間互相可見;
  • 已提交讀(READ COMMITED)符合隔離性的基本概念,一個事務進行時,其它已提交的事物對於該事務是可見的,便可以獲取其它事務提交的數據。
  • 可重複讀(REPEATABLE READ) InnoDB的默認隔離等級。事務進行時,其它全部事務對其不可見,即屢次執行讀,獲得的結果是同樣的!
  • 可串行化(SERIALIZABLE)在讀取的每一行數據上都加鎖,會形成大量的鎖超時和鎖徵用,嚴格數據一致性且沒有併發是可以使用。


查看系統的事務隔離級別:show variables like '%iso%';

開啓一個新事務:begin;

提交一個事務:commit;

修改事物的隔離級別:set session tx_isolation='read-committed';


④持久性(DURABILITY):從數據庫的角度的持久性,磁盤損壞就不行了




redo log機制保證事務更新的一致性和持久性。


3)大事務

運行時間長,操做數據比較多的事務。

風險:鎖定數據太多,回滾時間長,執行時間長。


  • 鎖定太多數據,形成大量阻塞和鎖超時;
  • 回滾時所需時間比較長,且數據仍然會處於鎖定;
  • 若是執行時間長,將形成主從延遲,由於只有當主服務器所有執行完寫入日誌時,從服務器纔會開始進行同步,形成延遲。


解決思路:


  • 避免一次處理太多數據,能夠分批次處理;
  • 移出沒必要要的SELECT操做,保證事務中只有必要的寫操做。


2、什麼影響了MySQL性能

一、影響性能的幾個方面

  • 服務器硬件。
  • 服務器系統(系統參數優化)。
  • 存儲引擎。
  • MyISAM: 不支持事務,表級鎖。
  • InnoDB: 支持事務,支持行級鎖,事務ACID。
  • 數據庫參數配置。
  • 數據庫結構設計和SQL語句。(重點優化)


二、MySQL體系結構

分三層:客戶端->服務層->存儲引擎



  • MySQL是插件式的存儲引擎,其中存儲引擎分不少種。只要實現符合mysql存儲引擎的接口,能夠開發本身的存儲引擎。
  • 全部跨存儲引擎的功能都是在服務層實現的。
  • MySQL的存儲引擎是針對表的,不是針對庫的。也就是說在一個數據庫中可使用不一樣的存儲引擎。可是不建議這樣作。


三、InnoDB存儲引擎

MySQL5.5及以後版本默認的存儲引擎:InnoDB。


1)InnoDB使用表空間進行數據存儲

show variables like 'innodb_file_per_table


  • 若是innodb_file_per_table 爲 ON 將創建獨立的表空間,文件爲tablename.ibd;
  • 若是innodb_file_per_table 爲 OFF 將數據存儲到系統的共享表空間,文件爲ibdataX(X爲從1開始的整數);


.frm :是服務器層面產生的文件,相似服務器層的數據字典,記錄表結構。


2)(MySQL5.5默認)系統表空間與(MySQL5.6及之後默認)獨立表空間

  • 系統表空間沒法簡單的收縮文件大小,形成空間浪費,並會產生大量的磁盤碎片。
  • 獨立表空間能夠經過optimeze table 收縮系統文件,不須要重啓服務器也不會影響對錶的正常訪問。
  • 若是對多個表進行刷新時,其實是順序進行的,會產生IO瓶頸。
  • 獨立表空間能夠同時向多個文件刷新數據。


強烈創建對Innodb使用獨立表空間,優化什麼的會更方即可控。


3)系統表空間的錶轉移到獨立表空間中的方法

  • 使用mysqldump 導出全部數據庫數據(存儲過程、觸發器、計劃任務一塊兒都要導出 )能夠在從服務器上操做。
  • 中止MYsql服務器,修改參數(my.cnf加入innodb_file_per_table),並刪除Inoodb相關文件(能夠重建Data目錄)。
  • 重啓MYSQL,並重建Innodb系統表空間。
  • 從新導入數據。


或者Alter table一樣能夠的轉移,可是沒法回收系統表空間中佔用的空間。


四、InnoDB存儲引擎的特性

1)特性一:事務性存儲引擎及兩個特殊日誌類型:Redo Log和Undo Log

  • Innodb 是一種事務性存儲引擎。
  • 徹底支持事務的ACID特性。
  • 支持事務所須要的兩個特殊日誌類型:Redo Log 和Undo Log


Redo Log:實現事務的持久性(已提交的事務)。

Undo Log:未提交的事務,獨立於表空間,須要隨機訪問,能夠存儲在高性能io設備上。


Undo日誌記錄某數據被修改前的值,能夠用來在事務失敗時進行rollback;Redo日誌記錄某數據塊被修改後的值,能夠用來恢復未寫入data file的已成功事務更新的數據。

2)特性二:支持行級鎖

  • InnoDB支持行級鎖。
  • 行級鎖能夠最大程度地支持併發。
  • 行級鎖是由存儲引擎層實現的。


五、什麼是鎖

1)鎖




2)鎖類型




3)鎖的粒度

MySQL的事務支持不是綁定在MySQL服務器自己,而是與存儲引擎相關。





將table_name加表級鎖命令:lock table table_name write; 寫鎖會阻塞其它用戶對該表的‘讀寫’操做,直到寫鎖被釋放:unlock tables;


  • 鎖的開銷越大,粒度越小,併發度越高。
  • 表級鎖一般是在服務器層實現的。
  • 行級鎖是存儲引擎層實現的。innodb的鎖機制,服務器層是不知道的。


4)阻塞和死鎖

  • 阻塞是因爲資源不足引發的排隊等待現象。
  • 死鎖是因爲兩個對象在擁有一份資源的狀況下申請另外一份資源,而另外一份資源剛好又是這兩對象正持有的,致使兩對象沒法完成操做,且所持資源沒法釋放。


六、如何選擇正確的存儲引擎

參考條件:


  • 事務
  • 備份(Innobd免費在線備份)
  • 崩潰恢復
  • 存儲引擎的特有特性


總結:Innodb大法好。

注意:儘可能別使用混合存儲引擎,好比回滾會出問題在線熱備問題。


七、配置參數

1)內存配置相關參數

  • 肯定可使用的內存上限。
  • 內存的使用上限不能超過物理內存,不然容易形成內存溢出;(對於32位操做系統,MySQL只能試用3G如下的內存。)
  • 肯定MySQL的每一個鏈接單獨使用的內存。


sort_buffer_size #定義了每一個線程排序緩存區的大小,MySQL在有查詢、須要作排序操做時纔會爲每一個緩衝區分配內存(直接分配該參數的所有內存);

join_buffer_size #定義了每一個線程所使用的鏈接緩衝區的大小,若是一個查詢關聯了多張表,MySQL會爲每張表分配一個鏈接緩衝,致使一個查詢產生了多個鏈接緩衝;

read_buffer_size #定義了當對一張MyISAM進行全表掃描時所分配讀緩衝池大小,MySQL有查詢須要時會爲其分配內存,其必須是4k的倍數;

read_rnd_buffer_size #索引緩衝區大小,MySQL有查詢須要時會爲其分配內存,只會分配須要的大小。

注意:以上四個參數是爲一個線程分配的,若是有100個鏈接,那麼須要×100。


  • MySQL數據庫實例:
  • ①MySQL是單進程多線程(而oracle是多進程),也就是說MySQL實例在系統上表現就是一個服務進程,即進程;
  • ②MySQL實例是線程和內存組成,實例纔是真正用於操做數據庫文件的;
  • 通常狀況下一個實例操做一個或多個數據庫;集羣狀況下多個實例操做一個或多個數據庫。


2)如何爲緩存池分配內存

Innodb_buffer_pool_size,定義了Innodb所使用緩存池的大小,對其性能十分重要,必須足夠大,可是過大時,使得Innodb 關閉時候須要更多時間把髒頁從緩衝池中刷新到磁盤中;



總內存-(每一個線程所須要的內存*鏈接數)-系統保留內存

key_buffer_size,定義了MyISAM所使用的緩存池的大小,因爲數據是依賴存儲操做系統緩存的,因此要爲操做系統預留更大的內存空間;



select sum(index_length) from information_schema.talbes where engine='myisam'

注意:即便開發使用的表所有是Innodb表,也要爲MyISAM預留內存,由於MySQL系統使用的表仍然是MyISAM表。


max_connections控制容許的最大鏈接數,通常2000更大。不要使用外鍵約束保證數據的完整性。


八、性能優化順序

從上到下:





3、數據庫結構優化


一、數據庫結構優化目的

  • 減小數據冗餘:(數據冗餘是指在數據庫中存在相同的數據,或者某些數據能夠由其餘數據計算獲得),注意,儘可能減小不表明徹底避免數據冗餘;
  • 儘可能避免數據維護中出現更新,插入和刪除異常:

  • 總結:要避免異常,須要對數據庫結構進行範式化設計。
  • 節約數據存儲空間。
  • 提升查詢效率。


二、數據庫結構設計步驟

  • 需求分析:全面瞭解產品設計的存儲需求、數據處理需求、數據安全性與完整性;
  • 邏輯設計(重要):設計數據的邏輯存儲結構。數據實體之間的邏輯關係,解決數據冗餘和數據維護異常。數據範式能夠幫助咱們設計;
  • 物理設計:表結構設計,存儲引擎與列的數據類型;
  • 維護優化:索引優化、存儲結構優化。


三、數據庫範式設計與反範式化

可參考「數據庫邏輯設計之三大範式通俗理解,一看就懂,書上說的太晦澀」

四、物理設計






可參考「MySQL中字段類型與合理的選擇字段類型;int(11)最大長度是多少?,varchar最大長度是多少」

4、高可用架構設計








一、讀寫分離



5、數據庫索引優化


一、兩種主要數據結構:B-tree和Hash

1)B-tree結構




B-tree索引的限制:




2)Hash結構




Hash索引的限制:

  • Hash索引必須進行二次查找
  • Hash索引沒法用於排序
  • Hash索引不支持部分索引查找也不支持範圍查找
  • Hash索引中Hash碼的計算可能存在Hash衝突,不適合重複值很高的列,如性別,身份證比較合適。


3)MySQL常見索引和各類索引區別


PRIMARY KEY(主鍵索引) ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` )

UNIQUE(惟一索引) ALTER TABLE `table_name` ADD UNIQUE (`column`)

INDEX(普通索引) ALTER TABLE `table_name` ADD INDEX index_name ( `column` )

FULLTEXT(全文索引) ALTER TABLE `table_name` ADD FULLTEXT ( `column` )

組合索引 ALTER TABLE `table_name` ADD INDEX index_name ( `column1`, `column2`, `column3` )


  • 普通索引:最基本的索引,沒有任何限制
  • 惟一索引:與"普通索引"相似,不一樣的就是:索引列的值必須惟一,但容許有空值。
  • 主鍵索引:它 是一種特殊的惟一索引,不容許有空值。
  • 全文索引:僅可用於 MyISAM 表,針對較大的數據,生成全文索引很耗時好空間。
  • 組合索引:爲了更多的提升mysql效率可創建組合索引,遵循「最左前綴」原則。


二、使用索引好處和索引缺陷

1)爲何要使用索引

  • 索引大大減小了存儲引擎須要掃描的數據量;
  • 索引能夠幫助咱們進行排序以免使用臨時表;
  • 索引能夠把隨機I/O變爲順序I/O。


2)索引不是越多越好

  • 索引會增長寫操做的成本;
  • 太多的索引會增長查詢優化器的選擇時間。



索引就比如一本書的目錄,它會讓你更快的找到內容,顯然目錄(索引)並非越多越好,假如這本書1000頁,而有500頁是目錄,它固然效率低,目錄是要佔紙張的,而索引是要佔磁盤空間的。


三、索引優化策略

1)索引列上不能使用表達式和函數




2)前綴索引和索引列的選擇性

Innodb索引列最大寬度爲667個字節(utf-8 差很少255個字符),MyIsam索引類寬度最大爲1000個字節,因而出現前綴索引,索引的選擇性。

對於列的值較長,好比BLOB、TEXT、VARCHAR,就必須創建前綴索引,即將值的前一部分做爲索引。這樣既能夠節約空間,又能夠提升查詢效率。但沒法使用前綴索引作 ORDER BY 和 GROUP BY,也沒法使用前綴索引作覆蓋掃描。

語法: ALTER TABLE table_name ADD KEY(column_name(prefix_length))




如何選擇索引列的順序:

  • 常常會被使用到的列優先(選擇性差的列不適合,如性別,查詢優化器可能會認爲全表掃描性能更好);
  • 選擇性高的列優先;
  • 寬度小的列優先(一頁中存儲的索引越多,下降I/O,查找越快);


3)組合/聯合索引策略

若是索引了多列,要遵照最左前綴法則。指的是查詢從索引的最左前列開始而且不跳過索引中的列。

4)覆蓋索引策略

跟組合索引有點相似,若是索引包含全部知足查詢須要的數據的索引則成爲覆蓋索引(Covering Index),也就是平時所說的不須要回表操做。即索引的葉子節點上面包含了他們索引的數據(hash索引不能夠)。

判斷標準:使用explain,能夠經過輸出的extra列來判斷,對於一個索引覆蓋查詢,顯示爲using index,MySQL查詢優化器在執行查詢前會決定是否有索引覆蓋查詢。

優勢:

  • 能夠優化緩存,減小磁盤IO操做;
  • 能夠減小隨機IO,變隨機IO操做變爲順序IO操做;
  • 能夠避免對InnoDB主鍵索引的二次查詢;
  • 能夠避免MyISAM表進行系統調用;


沒法使用覆蓋索引的狀況:

  • 存儲引擎不支持覆蓋索引;
  • 查詢中使用了太多的列(如SELECT * );
  • 使用了雙%號的like查詢(底層API所限制);

5)SQL索引優化總結口訣(套路重點)

全值匹配我最愛,最左前綴要遵照;

帶頭大哥不能死,中間兄弟不能斷;

索引列上不計算,範圍以後全失效;

LIKE百分寫最右,覆蓋索引不寫 *;

不等空值還有or,索引失效要少用;

字符單引不可丟,SQL高級也不難 ;

四、使用索引來優化查詢

1)利用索引排序

  • group by 實質是先排序後分組,遵守索引的最佳左前綴;
  • 索引中全部列的方向(升序、降序)和Order By子句徹底一致;
  • 當沒法使用索引列,增大max_length_for_sort_data參數的設置+增大sort_buffer_size參數的設置;
  • 若是最左列使用了範圍,則排序會失效;
  • where 高於having,能寫在where限定的條件就不要去having去限定了


五、索引的維護和優化

1)刪除重複索引




注:主鍵約束至關於(惟一約束 + 非空約束)

一張表中最多有一個主鍵約束,若是設置多個主鍵,就會出現以下提示:Multiple primary key defined!!!

2)刪除冗餘索引




檢查工具:pt-duplicate-key-checker

  • Using where:表示優化器須要經過索引回表查詢數據;
  • Using index:表示直接訪問索引就足夠獲取到所須要的數據,不須要經過索引回表,如覆蓋索引;


6、SQL查詢優化


一、獲取有性能問題SQL的三種方式

  • 經過用戶反饋獲取存在性能問題的SQL;
  • 經過慢查日誌獲取存在性能問題的SQL;
  • 實時獲取存在性能問題的SQL;


1)慢查日誌分析工具

相關配置參數:


slow_query_log # 啓動中止記錄慢查日誌,慢查詢日誌默認是沒有開啓的能夠在配置文件中開啓(on)

slow_query_log_file # 指定慢查日誌的存儲路徑及文件,日誌存儲和數據從存儲應該分開存儲

long_query_time # 指定記錄慢查詢日誌SQL執行時間的閥值默認值爲10秒一般,對於一個繁忙的系統來講,改成0.001秒(1毫秒)比較合適

log_queries_not_using_indexes #是否記錄未使用索引的SQL


經常使用工具:mysqldumpslow和pt-query-digest


pt-query-digest --explain h=127.0.0.1,u=root,p=p@ssWord slow-mysql.log


2)實時獲取有性能問題的SQL(推薦)





SELECT id,user,host,DB,command,time,state,info

FROM information_schema.processlist

WHERE TIME>=60


查詢當前服務器執行超過60s的SQL,能夠經過腳本週期性的來執行這條SQL,就能查出有問題的SQL。

二、SQL的解析預處理及生成執行計劃

1)查詢過程描述



經過上圖能夠清晰的瞭解到MySQL查詢執行的大體過程:

  • 發送SQL語句。
  • 查詢緩存,若是命中緩存直接返回結果。
  • SQL解析,預處理,再由優化器生成對應的查詢執行計劃。
  • 執行查詢,調用存儲引擎API獲取數據。
  • 返回結果。


2)查詢緩存對性能的影響(建議關閉緩存)

第一階段:

相關配置參數:


query_cache_type # 設置查詢緩存是否可用

query_cache_size # 設置查詢緩存的內存大小

query_cache_limit # 設置查詢緩存可用的存儲最大值(加上sql_no_cache能夠提升效率)

query_cache_wlock_invalidate # 設置數據表被鎖後是否返回緩存中的數據

query_cache_min_res_unit # 設置查詢緩存分配的內存塊的最小單


緩存查找是利用對大小寫敏感的哈希查找來實現的,Hash查找只能進行全值查找(sql徹底一致),若是緩存命中,檢查用戶權限,若是權限容許,直接返回,查詢不被解析,也不會生成查詢計劃。

在一個讀寫比較頻繁的系統中,建議關閉緩存,由於緩存更新會加鎖。將query_cache_type設置爲off,query_cache_size設置爲0。

3)第二階段:MySQL依照執行計劃和存儲引擎進行交互

這個階段包括了多個子過程:




一條查詢能夠有多種查詢方式,查詢優化器會對每一種查詢方式的(存儲引擎)統計信息進行比較,找到成本最低的查詢方式,這也就是索引不能太多的緣由。

三、會形成MySQL生成錯誤的執行計劃的緣由

  • 統計信息不許確
  • 成本估算與實際的執行計劃成本不一樣


  • 給出的最優執行計劃與估計的不一樣


  • MySQL不考慮併發查詢
  • 會基於固定規則生成執行計劃
  • MySQL不考慮不受其控制的成本,如存儲過程,用戶自定義函數


四、MySQL優化器可優化的SQL類型

查詢優化器:對查詢進行優化並查詢MySQL認爲的成本最低的執行計劃。爲了生成最優的執行計劃,查詢優化器會對一些查詢進行改寫。

能夠優化的SQL類型:

  • 從新定義表的關聯順序;



  • 將外鏈接轉換爲內鏈接;
  • 使用等價變換規則;



  • 優化count(),min(),max();


  • 將一個表達式轉換爲常數;
  • 子查詢優化;


  • 提早終止查詢,如發現一個不成立條件(如where id = -1),當即返回一個空結果;
  • 對in()條件進行優化;


五、查詢處理各個階段所須要的時間

1)使用profile(目前已經不推薦使用了)


set profiling = 1; #啓動profile,這是一個session級的配製執行查詢

show profiles; # 查詢每個查詢所消耗的總時間的信息

show profiles for query N; # 查詢的每一個階段所消耗的時間


2)performance_schema是5.5引入的一個性能分析引擎(5.5版本時期開銷比較大)

啓動監控和歷史記錄表:use performance_schema


update setup_instruments set enabled='YES',TIME = 'YES' WHERE NAME LIKE 'stage%';

update set_consumbers set enabled='YES',TIME = 'YES' WHERE NAME LIKE 'event%';








六、特定SQL的查詢優化

1)大表的數據修改







2)大表的結構修改




利用主從複製,先對從服務器進入修改,而後主從切換。

添加一個新表(修改後的結構),老表數據導入新表,老表創建觸發器,修改數據同步到新表,老表加一個排它鎖(重命名),新表重命名,刪除老表。




修改語句這個樣子:


alter table sbtest4 modify c varchar(150) not null default ''


利用工具修改:




3)優化not in 和 <> 查詢

子查詢改寫爲關聯查詢:




7、分庫分表


一、分庫分表的幾種方式

分擔讀負載 可經過 一主多從,升級硬件來解決。

1)把一個實例中的多個數據庫拆分到不一樣實例(集羣)




拆分簡單,不容許跨庫。但並不能減小寫負載。

2)把一個庫中的表分離到不一樣的數據庫中




該方式只能在必定時間內減小寫壓力。

以上兩種方式只能暫時解決讀寫性能問題。

3)數據庫分片

對一個庫中的相關表進行水平拆分到不一樣實例的數據庫中:




如何選擇分區鍵

  • 分區鍵要能儘量避免跨分區查詢的發生
  • 分區鍵要儘量使各個分區中的數據平均


分片中如何生成全局惟一ID



歡迎工做一到五年的Java工程師朋友們加入Java程序員開發: 854393687

羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用本身每一分每一秒的時間來學習提高本身,不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代!

相關文章
相關標籤/搜索