mysql相關問題總結


  mysql我們經常使用,但是我們對其中的知識也要了解和熟悉,我們需要做一下必要的總結,方便自己和同學們一起學習。接下來我們一起來看看平時我們需要了解和掌握的知識有哪些。

  1. myisam和innodb的區別?

  2. mysql的幾種事務隔離級別。

  3. 什么是聚簇索引和非聚簇索引。

  4. 什么是覆蓋索引、回表。

  5. ACID是如何保證的。

  6. 主從是如何同步的,有什么缺點?

  

1. myisam和innodb的區別。

  myisam是之前mysql的默認引擎,主要用於讀大於寫的時候使用,數據存放在內存中,這樣讀的速度非常快,但是當數據庫重啟之后數據將需要重新加載到內存中。這個引擎從5.1之前都是默認的引擎。但是它不支持事務、行鎖、外鍵,這些都是它的缺點。

  innodb的產生就是為了解決它的缺點。innodb支持事務、行鎖、外鍵。現在非常流行的就是這個數據庫引擎。通過MVCC實現高並發訪問。

 

2.mysql的幾種事務隔離級別。

 mysql支持未提交讀,已提交讀,可重復讀,串行Serializable。mysql默認隔離級別為可重復讀,oracle的默認隔離級別為已提交讀。

 未提交讀(Read Uncommitted) :即事務還沒有提交的時候別的事務可以查看到數據,也成為臟讀。舉個例子,

 事務A,查詢id=1的name,此時name為hqs。

 事務B,更新id=1的name為hhh。我們將看到如下的結果:

 

   已提交讀(Read Committed),  當事務提交的了之后,另外一個事務才能看到。不會出現上邊的問題,即不會出現臟讀,但是在這個過程中會出現不可重復讀,接下來我們繼續看,基本上還是剛才的例子。

   可重復讀(Read Repeatable):每次可以正確的讀取數據的結果,但是會出現幻讀,接下來我們看看這種情況。

  說道可重復讀,我們需要了解一下他是如何實現的。它采用MVCC(Multi Version Concurency Control), 多版本並發控制,類似於數據庫的樂觀鎖,通過版本號來控制該讀哪個版本號的數據,實現對數據的高並發訪問。

  首先我們需要知道什么是undolog,redolog,binlog。

  undolog,即未做日志,也就是加入數據庫里邊有一條id=1 and name='hqs'的數據,那么我修改了這個數據的name='hhh',當事務提交了之后,會有一條undolog,這個時候執行的語句就是update table set name='hqs' where id=1,即還原之前的數據。相應的如果有一條insert語句會有一條對應的delete語句,當事務出現了問題之后需要回滾到上一個版本上。這個也是mvcc的關鍵。

  redolog,數據庫的操作過程是非常快速的,一般執行數據庫操作的時候需要將數據先寫入到緩存,即write ahead log,比如寫入數據會有一條insert語句,更新會有一條update語句等,這個時候需要先寫到緩存中,然后當執行成功后會刷到磁盤上。這個時候實現了快速的處理和寫入。寫入緩存的時候為parepare,寫完之后即變為commit,這也就是兩階段提交時進行的數據處理,當commit之后然后就可以flush到磁盤上。

  binlog,即所有引擎日志,數據有了之后就有這個日志,記錄了server的操作日志。用於主從復制,數據恢復時使用,這個需要定時保存。

  數據庫在執行了事務之后,每條記錄除了數據之外,還有幾個關鍵字段db_trx_id, db_roll_ptr。

  db_trx_id,即執行事務的id。

  db_roll_ptr,事務回滾的指針,用於指向undolog的記錄,當事務執行失敗之后需要需要回滾到之前的版本號。

 

 

     

  MVCC就是采用事務版本號進行讀取的,當commit之后,我們知道最后一個事務成功的版本號,然后根據這個版本號產生一個讀視圖(read view),通過讀視圖讀取數據時,這個時候就能正確的讀取數據。

  那我們知道了可重復讀的隔離情況下,如何解決幻讀呢?

  假如我們數據庫里邊有這幾條數據。

 

 

   這個時候我們執行下邊的兩條事務,第一條語句執行的時候加了行鎖,然后第二條語句開始進行寫入。

begin;
select * from table where age = 20 for update;


begin;
insert into table (name, age) values (h4, 10); #成功
insert into table (name, age) values (h5, 20); #失敗
insert into table (name, age) values (h6, 25); #失敗
insert into table (name, age) values (h7, 30); #失敗

  這個時候就出現了Gap Lock,這個是可重復讀隔離級別獨有的。通過這種方式可以獲取“當前讀”,即當前最新的數據,避免產生幻讀。行鎖+間隙所解決幻讀的問題。

  關於間隙鎖,我們接下來繼續認識一下。以上數據產生的間隙鎖如下(左包含右邊不包含):

(負無窮, 10], (10 20], (20, 30], (30, 正無窮)

  因為數據里邊有age=20的記錄,所以(10, 20]會鎖定,這些記錄段的數據不能進行更新操作。所以10成功了,20失敗了之后,后邊的就全部失敗了,因為有失敗了之后進行了數據的回滾。

  如果索引是唯一索引的話不存在間隙鎖。

  基於上邊的總結,我整理出一個表格可以更清晰的認識這個事務的級別。 

      

3. 什么是聚簇索引和非聚簇索引。

  每個表都有一個唯一主鍵,唯一主鍵形成的索引樹就是聚簇索引,采用B+樹進行的數據存儲。每個節點存儲這個數據的索引id,一層一層的按范圍分的,越往上越范圍越大,越往下范圍越小。葉子節點存儲的真實的數據,真實的數據是id從小到大的數據進行分布的,數據采用雙向鏈表用於數據的快速查找。如下圖所示:

 

 

   非聚簇索引也稱為非主索引,加入以name+age為索引的話,那么效果就是這樣的,根據索引字段生成一個索引id,然后索引id和主鍵形成一個映射。然后再根據主鍵進行數據的查詢。效果如下:

  

 

 

4. 什么是覆蓋索引、回表。

  覆蓋索引理解起來比較簡單,即執行explain的時候的時候提示“using index”,即使用了覆蓋索引。

  比如有一個table,有表A、B、C字段,假如有index( A,B,C) 那么,我們查詢順序A, AB, ABC的時候,都是采用覆蓋索引。

  當我們使用字段B,C的時候,那么沒有走到數據庫的索引,這個時候需要先查詢到索引對應的主鍵id,然后再進行二次查詢,這個就是回表。

  

5. ACID是如何保證的。  

  A原子性,通過undolog保證,當事務執行失敗的時候,通過unlog將數據還原來保證事務的一致性。

  C一致性,當兩個事務提交后,最終能保證數據的結果是一致的。

  I隔離性,通過MVCC來保證。

  D持久性,通過內存+redolog,數據一般會刷到內存,然后事務提交之后再刷到磁盤上。當數據有問題的時候通過redolog來進行數據恢復。

6. 主從是如何同步的,有什么缺點?

  主從同步,分為幾個步驟:

  1. master寫入binlog。

  2. slave連接到master,並且記錄好binlog的id.

  3. master的binlog進行slave日志同步。

  4. slave開啟一個線程,讀取binlog的日志,然后寫到中繼日中relaylog中。

  5. slave在開啟一個線程,從relaylog讀取日志之后寫到slave數據庫看。

  6. slave會記錄到自己的數據庫中。

 

  如下圖所示:

  

 

 

  由於默認mysql同步日志是采用異步的,所以主庫寫入不寫入從庫,主庫不關心,這個時候從庫出現了問題的話,主庫無感知。如果主庫失敗了,那么從庫讀取失敗的話,從庫升級為主庫,日志就丟失了。這個時候就會出現兩種情況:

  全同步復制:

    全同步就是當主庫往從庫寫數據采用的同步處理,這個時候主庫寫完binlog,然后等待從庫處理完成,這樣會影響效率。

  半同步復制:

    半同步是在數據發給從庫后,從庫處理完之后會發一個ACK給主庫,這樣主庫就知道了,然后確認傳輸完成。

  當然,我們除了數據庫的解決數據丟失問題,我們還需要程序來保證額外的數據冗余處理,比如將傳輸的數據發送到MQ或KAFKA,其他系統可以從這個里邊去讀取,然后進行下一步處理。保證數據的安全可靠。

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM