天天看點

mysql 檢視函數fsync_mysql

mysql 檢視函數fsync_mysql

什麼是MVCC?原理是什麼樣的?

MVCC是InooDB中的多版本控制,是一種并發控制。當事務執行的時候會生成一個readview,在不同的隔離級别下生成readview的時機也不一樣,MVCC支援RC和RR兩種隔離級别,它們生成readview的時機分别是:

RR:在第一條select語句執行的時候,後面的事務内語句共用這個readview

RC:在每一條select語句執行的時候都要建立readview

readview包含兩個東西,一個是建立readview的時候所有活躍的事務id數組,它的最小值就是低水位,以及所有建立事務的id中最大值+1,為高水位。

在UNDOlog中包含資料的各個版本資訊,其中這個版本就是對這個資料進行更改的事務ID号,當事務去取自己應該看見的值的版本的時候,有三種情況:

1、 版本在低水位之下:在視圖建立前已經送出的事務,可見。

2、 版本在高水位之上:在視圖生成的時候還沒建立的事務,不可見

3、 版本在低水位高水位之間:1.在數組中表示在視圖建立的時候還沒送出不可見。2.不再數組中,表示已經送出了,可見。

當系統裡沒有比這個復原日志更早的 read-view 的時候,會删除舊的undolog

索引的選擇/如果一個sql很慢是什麼原因:

首先建立索引的時候可以使用覆寫索引減少回表,或者使用聯合索引搭配最左字首原則來減小索引的數目,減小維護的一個成本。還有當聯合索引比對的時候如果打破了最左字首,比如like,可以使用5.6的索引下推功能進一步的做條件比對,減小回表的次數,如果是機械硬碟的,随機讀寫開銷很大,可以開啟mrr,Multi range read,使用一個buffer來對主鍵一個排序,将随機讀取轉為順序讀取。另外如果業務能保證唯一性的時候,且對于寫多讀少的業務來說。可以使用普通索引代替唯一索引,因為普通索引實際上有一個change buffer,能夠先把更改緩存下來,當需要使用的時候再把資料頁從磁盤讀到記憶體然後執行change buffer中和這個頁有關的操作,merge到資料頁上,可以減小磁盤的随機通路。

sql很慢的原因可能是索引取錯了,可以使用慢查詢日志,set long_querytime=0,分别對應該選中的索引(force index)和實際選中的索引進行分析,通過rows_examined字段可以看到執行器調用的次數。可能是優化器在算基數的時候可能出現了錯誤,優化器中掃描行數是影響代價的因素之一。但不是唯一标準,還會結合是否使用臨時表、是否排序等因素綜合判斷。那麼為了更準确,可以先檢視一下基數,這就是索引的統計資訊,使用show index檢視,還可以使用explain來看rows字段是不是和預估的差不多,如果差的多,

可以使用analyze table指令,重新計算表的統計資訊。或者臨時的使用force index。或者修改sql語句引導優化器知行希望的索引。在有些場景下,我們可以建立一個更合适的索引,來提供給優化器做選擇,或删掉誤用的索引。

在刷髒頁,比如redolog寫滿了,就需要flush到硬碟上。或者記憶體不足,需要淘汰一些髒頁,在淘汰前就需要flush到硬碟。寫操作會瞬間跌到0,innodb_io_capacity可以控制刷髒頁的速度,innodb_max_dirty_pages_pct 是髒頁比例上限。在硬碟性能還不錯的時候盡量的提高這個值,可以盡快的将髒頁重新整理到硬碟。一旦一個查詢請求需要在執行過程中先 flush 掉一個髒頁時,這個查詢就可能要比平時慢了。而且mysql中還會連帶把鄰居一起重新整理,如果使用機械硬碟的話還可以,因為你會減小很多随機io,但比較好的硬碟的話,盡量關閉這個功能。

是否有隐形的函數轉換,比如字段類型不一樣,可能會對性能有一定的影響

表項太多,空洞太多,可以使用alter table來重建表。

show processlist可以看看是不是在等待鎖。

或者是不是更新操作頻繁,導緻undolog很長。

binlog和redolog

首先是兩階段送出

mysql 檢視函數fsync_mysql

如果 redo log 裡面的事務是完整的,也就是已經有了 commit 辨別,則直接送出;

如果 redo log 裡面的事務隻有完整的 prepare,則判斷對應的事務 binlog 是否存在并完整:a. 如果是,則送出事務;b. 否則,復原事務。

那麼mysql是怎麼知道binlog是完整的?statement的binlog最後會有一個commit,row 格式的 binlog,最後會有一個 XID event。在5.6.2以後還引入了binlog-checksum用來驗證 binlog 内容的正确性。redolog和bilog有個共同的字段XID,崩潰恢複的時候,會順序掃描redolog,如果碰到既有 prepare、又有 commit 的 redo log,就直接送出;如果碰到隻有 parepare、而沒有 commit 的 redo log,就拿着 XID 去 binlog 找對應的事務。

不使用兩階段送出就會出現問題,反正一下,要麼先寫完redolog再寫binlog,要麼先寫完binlog再寫redolog。前者的話,如果binlog不完整redolog完整,就會導緻主從不一緻。如果是後者的話,在redolog前崩潰就會判斷失誤是無效的,但是binlog裡記錄了這個日志,是以回複的時候就會多一個事務出來。

為什麼不用一個日志就好了?首先binlog恢複時機控制不好,因為MySQL寫資料是寫在記憶體裡的,不保證落盤,是以commit1的資料也可能丢失;但是恢複隻恢複binlog失敗的也就是commit2的資料,是以資料會丢失。再者binlog也沒那個能力,因為沒有頁面資訊。

使用redolog恢複的過程也是先寫髒頁再持久化到硬碟,不會直接從redolog到硬碟。

binlog和redolog寫入時機

binlog 的寫入邏輯比較簡單:事務執行過程中,先把日志寫到 binlog cache,事務送出的時候,再把 binlog cache 寫到 binlog 檔案中。

write 和 fsync 的時機,是由參數 sync_binlog 控制的

sync_binlog=0 的時候,表示每次送出事務都隻 write,不 fsync;sync_binlog=1 的時候,表示每次送出事務都會執行 fsync;sync_binlog=N(N>1) 的時候,表示每次送出事務都 write,但累積 N 個事務後才 fsync。

InnoDB 提供了 innodb_flush_log_at_trx_commit 參數

設定為 0 的時候,表示每次事務送出時都隻是把 redo log 留在 redo log buffer 中 ;設定為 1 的時候,表示每次事務送出時都将 redo log 直接持久化到磁盤;設定為 2 的時候,表示每次事務送出時都隻是把 redo log 寫到 page cache。

explain的字段

mysql 檢視函數fsync_mysql

主備一緻

mysql 檢視函數fsync_mysql

每次對主庫的更新都會被同步到備庫。

一般都将備庫設定為read-only的,因為防止誤操作,防止切換的時候有bug,出現雙寫,在一個也比較容易判斷身份。但是隻讀對超級權限無效,可以用超級權限來更新。

mysql 檢視函數fsync_mysql

流程如上圖,首先使用change master設定主庫的ip端口使用者名密碼,以及從哪一個位置開始請求binlog。執行start slave,就是iothread和sqlthread,主庫從本地讀取binlog,發送給從庫,拿到binlog以後寫到本地檔案,為relaylog 然後執行。