mysql相關問題總結

黃青石發表於2020-09-06

  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,其他系統可以從這個裡邊去讀取,然後進行下一步處理。保證資料的安全可靠。

  

  

相關文章