1. 程式人生 > >偽MySQL面試寶典(一)

偽MySQL面試寶典(一)

簡單說明:

以下資訊整理至網路部落格,是總結匯總,後期看情況可能有後續博文,不確定

資料庫事務ACID:

原子性(Atomic):事務中的多個操作,不可分割,要麼都成功,要麼都失敗
一致性(Consistency):事務是由單條或者多條DML組成
    事務發生後,表結構、約束,和事務不相關的表物件等資料和結構保持不變
    例1,表某欄位有主鍵約束,事務DML不會造成主鍵失效,並且不滿足主鍵唯一的約束時,事務失敗
    例2,create table testabc ( n1 number,n2 number,check(n1+n2=10));
    當事務update改變了n1的值,而沒有改變n2的值,check
約束不滿足,則事務失敗 隔離性(Isolation): 多個事務之間就像是序列執行一樣,不相互影響 永續性(Durability):事務提交後被持久化到永久儲存,不會丟失也不是回滾

ACID中隔離性最複雜:

READ UNCOMMITTED:RU,可以讀未提交資料,未提交資料為髒資料,即可髒讀,也就是事務之間沒有隔離
                  不允許重複讀,允許幻讀和髒讀
READ COMMITTED:  RC,只能讀取已經提交的資料,事務之間隔離,資料提交後可被其他事務讀取
                  允許幻讀,不允許重複讀,不允許髒讀
REPEATABLE READ
: RR,可重複讀,一個事物中多次執行同一個select,資料不變,MVCC實現 允許幻讀和可重複讀,不允許髒讀 SERIALIZABLE: 不允許髒讀和幻讀,可重複讀,相當於單會話單事務庫

關於隔離性的幾個概念:

髒讀:其他事務可以讀取未提交資料
重複讀:一個事物中多次執行同一個select,資料不變叫可重複讀,多版本併發控制MVCC實現
        資料變化(其他會話的其他事務做了update並提交),叫不可重複讀
幻讀:一個事務中多次執行同一個select, 讀取到的資料行發生改變,行數減少或者增加
        其他會話的其他事務做了delete
/insert並且提交 重複讀和幻讀區別: 重複讀主要是併發會話的update操作是否對當前會話造成影響 幻讀主要是併發會話的delete/insert操作是否對當前會話造成影響

RC和RR比較:

Oracle預設RC,並且實現了SERIALIZABLE(基於undo的閃回版本查詢)

MySQL預設事務隔離級別是RR,使用多版本併發控制MVCC實現

MySQL使用gap lock+row lock形成的next-key lock來儘量避免幻讀
SERIALIZABLE使用讀和寫均加鎖的方式實現

也有很多場景將MySQL的事務隔離級別從RR降級成RC的,RC和RR比較如下:
RR在RC的基礎上加了gap lock,它和RC的row lock形成的next-key lock鎖
所以RC的併發好於RR,鎖少併發高,隔離性差
比如 一個會話 delete 一張表,where條件有兩個,第一個限定了影響範圍是5條資料
第二個限定了5條資料中的確定1行,如果是RC的話,row lock只會鎖最終被delete的那一行
如果RR的話,會話不提交,那麼根據第一個條件篩選出來的記錄以及記錄前後的記錄都會被鎖定
這個鎖是gap lock造成的,然後事務提交或回滾後才會釋放,這就導致了被gap lock鎖定的記錄無法被delete掉
這就是RR模式下使用gap lock來儘量避免幻讀的情況,gap lock出現於範圍過濾條件

多版本併發控制MVCC:

MySQL的預設事務隔離級別是RR,由多版本併發控制MVCC實現
1,每一行記錄後面都有隱藏的兩列,記錄建立版本號和刪除版本號
每一個事務在啟動的時候,都有一個唯一的遞增的版本號
2,記錄的建立版本號實際上就是記錄在被insert的時候的事務號
3update操作時,標記記錄為已刪除,記錄的刪除版本號就是update事務的版本號
然後插入一行新的記錄,記錄建立版本號就是update事務的版本號
4delete操作時,把事務版本號作為刪除版本號
5,MVCC實現可重複讀,是並行事務update操作對當前事務的影響
   設當前事務ID是5,並行事務ID是8,記錄的建立版本號是3
   1°事務5查詢到的記錄R是建立版本號為3的記錄
     記錄R,建立版本號3,刪除版本號nil
   2°事務8update的操作對記錄的影響:
   記錄R,建立版本號3,刪除版本號8
   記錄R,建立版本號8,刪除版本號nil
   3°事務5查詢到的記錄R是建立版本號為3的記錄
   4°MVCC版本控制原理:
     刪除版本號大於當前會話的事務版本號,刪除操作發生於當前事務之後
     建立版本號小於等於當前事務版本號,記錄是在當前事務或者之前事務插入的
     當這兩個條件滿足時,相應的記錄查詢出來,提高系統性能的思路:通過版本號來減少鎖的爭用

MySQL 鎖和索引:

InnoDB:行鎖和表鎖,預設行鎖

1,行鎖是通過給索引上的索引項加鎖來實現的
比如一張表主鍵id有索引,update更新id=1的這一行,最終鎖定的是主鍵索引的索引項
只有通過索引條件檢索資料,InnoDB才使用行級鎖,否則將使用表鎖,這一點要特別注意

2,相同的索引項不同記錄之間會出現衝突,非唯一性索引會鎖住多個記錄行
多個會話where條件class=1 and name=...,class列有索引,name列無索引,會話之間會有鎖衝突

3,表有多個索引,不同的事務使用不同的索引鎖定不同的行
行鎖適用於所有索引型別:主鍵索引、唯一索引或普通索引

InnoDB是支援事務的儲存引擎,預設事務隔離性RR級別
在行級鎖row lock之外增加了間隙鎖gap lock,形成了next key lock來儘量避免幻讀,沒有完全解決幻讀

4,間隙鎖gap lock出現在範圍條件過濾資料之時,比如n>1 and n<8,n列有索引
那麼會在n>=2且n<=8的記錄上加gap lock,來界定記錄範圍
如果n=2的記錄不存在,則順延到n=3
如果n=8的記錄不存在,則順延到n=9
在RR隔離級別下,gap lock鎖住了更多範圍的資料,避免了一部分的幻讀,但是也造成了鎖等待

5,表鎖應用場景:
事務需要更新大部分或全部資料,表又比較大
事務涉及多個表,比較複雜,很可能引起死鎖,造成大量事務回滾
應用中這兩種事務如果太多,則要考慮MyISAM引擎

6,MyISAM不存在死鎖,InnoDB存在,自動檢測,自動回退某事務,解決死鎖

MySQL備份和恢復:

邏輯備份:mysqldump,實際上是生成建庫、建表和資料插入等等的SQL語句的文字檔案
是邏輯備份,如果要做恢復的話,需要藉助binlog追平日誌,需要備份開始時候的binlog
備份時先將隔離級別強制改成RR,開啟備份程序,做回滾點標記,記錄LSN(log sequence number)
備份中不含該標記之後的事務,生成建庫、建表和資料插入的SQL,備份完成後釋放回滾點,隔離級別恢復
通過引數--master-data=1/2來控制列印binlog日誌資訊和pos位置

物理備份:Percona的XtraBackup,支援所有MySQL發行版,完全開源,是物理備份恢復工具
可以實現增量備份,具體就是比較資料檔案的page上的LSN,比已經備份的LSN大則進行備份
試用於innodb,MyISAM沒有增量,只有全量的資料檔案複製

PXB備份過程梳理:
innobackupex啟動xtrabackup程序
xtrabackup首先啟動單執行緒的redo備份,順序拷貝redo,然後啟動資料檔案備份
資料檔案備份完成後,通知innobackupex,建立檔案,redo的複製繼續
innobackupex執行FLUSH TABLES WITH READ LOCK (FTWRL),備份非innodb檔案
此時資料庫處於全域性只讀狀態,需要預估全域性只讀對業務的影響,或者使用備庫備份
備份非innodb檔案完成後,xtrabackup停止redo備份,然後通知innobackupex
innobackupex執行UNLOCK TABLES
恢復時需要備份完成之後的binlog做恢復,也就是說備份檔案中的LSN是備份完成之時的LSN
xtrabackup_info和xtrabackup_binlog_info檔案記錄binlog資訊

MySQL主備複製原理:

需要的條件:主庫開啟binlog,備庫可以通過網路訪問到主庫

主要執行緒:主庫IO,從庫IO和SQL,一個用於binlog資料傳輸,一個用於SQL應用

原理剖析:
主庫開啟binlog,配置使用者,做備份
備庫根據備份做恢復
備庫配置主從資訊master.info:主庫的IP、埠、使用者和binlog檔案以及POS位置資訊
start slave,開始複製:
備庫開啟IO和SQL程序,備庫IO通訊主庫,使主庫開啟IO程序
備庫根據master.info中的binlog和pos資訊以及主庫的使用者資訊
請求主庫的對應binlog,存入relay-log,重新整理master.info
備庫SQL程序應用relay-log

show slave status 檢視主從複製的延遲,具體是Seconds_Behind_Master

MySQL主備複製的GTID複製:

5.6開始支援的特性,GTID即是全域性事務ID,是事務的唯一標識
分成兩部分,一部分是服務的UUID,儲存在auto.cnf檔案中,該檔案不能刪除,是每個MySQL唯一的
另外一部分就是事務ID,隨著事務的增加,值遞增

主庫發生事務,會產生GTID,記錄到binlog中
備庫的IO執行緒將主庫binlog寫入relay log中
備庫的SQL執行緒從relay log中獲取GTID,然後比較備庫的binlog確定該事務是否已經在備庫執行
如果執行則忽略,如果沒有才會去執行,然後寫入備庫binlog

優點:
1,每個事務都擁有唯一的GTID,執行前會確認是否已經執行過,保證事務只執行一次
2,使用GTID進行主備複製,不再需要指定binlog位置和pos
傳統的主備是將主庫的binlog日誌傳送到備庫,然後將資訊追加到relay log中
而使用GTID進行主備複製,直接傳輸主庫變更的binlog到relay log中
3,三節點或者更多節點的主備複製切換中,可以更有效的定為事務是否被執行,減少事務丟失

限制:
1,只支援innodb事務引擎
2,create table as select 不支援,該類SQL實際上是兩個SQL,
   其中還有DDL會造成隱式提交,需要兩個GTID,但是目前只能生成一個
3,不允許一個SQL同時更新innodb和非innodb的表
4,主備複製要麼各節點均開啟GTID,要麼均關閉
55.6模式開啟需要重啟,5.7不需要
6,開啟GTID後,傳統模式將關閉
7,不支援臨時表的建立和刪除
8,不支援sql_slave_skip_counter

MySQL MHA 架構原理剖析:

MHA需要部署在至少是三節點的主備複製叢集之上,一臺master,一臺備master,一臺從庫
是對Master實時監控,故障自動切換Slave為Master的高可用套件
MHA由一個Manager節點和多個Node節點組成,每個MySQL無論主備都要部署Node節點
Manager節點對Node節點實時監控,發現Master不可用時,自動提升某個Slave為Master
一個Manager節點可以同時管理多套主備複製叢集
MHA控制主備切換時,會依據新主的relay-log向slave進行同步

MySQL 讀寫分離 兩種實現:

主備複製之後 程式碼層面多資料來源 設定select和其他DML分別接入備庫和主庫實現 程式碼層的實現
使用MySQL Proxy 中間套件實現 實際上就是所有web接入 MySQL Proxy
由 MySQL Proxy 統一接入到MySQL 並分析SQL型別接入到Master還是Slave

MySQL效能監控:

使用Zabbix的通用模板對MySQL進行監控,這是Zabbix自動化監控告警的方式

日檢或者周檢以及巡檢的時候監控點:
1,show processlist/show full processlist
監控當前或者問題時間點的SQL執行情況,分析多少會話在執行SQL
併發執行的SQL是什麼,等待事件是什麼,平均執行時間等
2show global status
監控該命令兩次輸出資料的差值來計算諸如:
這期間有多少次查詢請求、select/insert/update/delete運算元
innodb行讀取或者DML操作次數、Innodb_buffer相關等等的一系列監控
使用shell指令碼,以高階awk命令生成報表進行監控
3,定期對slow log進行切割轉儲,並使用工具生成報表,使用的工具是mysqlsla

詳見《MySQL健康檢查(一)》、《MySQL健康檢查(二)》

MySQL 線上DDL和pt-osc工具:

innodb對錶進行DDL的操作流程是建立一個相同結構的臨時表執行DDL
鎖定原表,將原表資料insert到臨時表,原表和臨時表改名切換,解鎖
原表鎖定階段無法DML,如果表比較大,鎖表時間就會很長,會影響正常的業務DML

5.6開始支援線上DDL
剔除鎖表操作,將線上DDL期間發生的DML操作寫入到快取中
最後將快取應用到臨時表,表名切換,完成線上DDL

Percona的開源工具pt-osc(pt-online-schema-change)
建立原表相同結構的空表,DDL改變結構
原表上增加DML觸發器
複製資料,包括觸發器生成的資料
表改名替換,刪除原表和觸發器

限制條件和注意事項:
表要有主鍵、不能有觸發器,如果有外來鍵約束需要專門處理

[TOC]