mysql 相關

antor發表於2024-08-11

1. mysql 索引

1.1 mysql 為什麼使用b+ 樹做索引

mysql 的索引主要有hash 索引以及B+樹索引
對於索引,一般就是為了加快資料訪問而存在的,所以索引要求的就是效率
而mysql 索引資料一般是儲存在磁碟的,磁碟與記憶體的互動存在IO, 而IO是硬體問題,沒法解決,剩下的能解決的也就是IO次數以及IO量
所以對於索引的設計,最好就是採用分塊讀取的方式,例如innodb 每次讀取都是16K
確定了索引的讀取方式之後,就是索引的型別,對於索引,其就是為了根據一部分資料來確定其他資料,所以最適合的結構就是kv
而kv的話,又包含了hash和各種樹。
所以mysql 存在hash 索引, 但是hash 的話一般是透過key 計算Hash 值,這樣沒法做範圍查詢,因為對key 做了二次計算。
然後是樹,樹的結構主要分為二叉樹和多叉樹等。對於二叉樹,其只有兩個分支,所以當資料量過多的話,就容易特別深,而對於 mysql ,
其儲存的資料量是沒有上限的,所以二叉樹等樹結構首先會被pass掉。
最後也就是多叉樹,對於多叉樹,有B樹,B+樹,N叉樹等,對於N叉樹,其節點雖然可以儲存更多的鍵值對,但是其的平衡維護起來比較複雜,不像B樹和B+樹,
可以很輕鬆的維護平衡,對於mysql查詢資料來說,會存在範圍查詢,而N叉樹的範圍查詢比起B和B+樹來說也是一大弱項,所以N叉樹被pass
然後是B樹和B+樹,對於B樹,其非葉子節點不只儲存索引資訊,還會儲存資料資訊,而B+樹,非葉子節點只儲存索引資訊,同時對於其葉子節點還有左右指標,方便範圍查詢
所以B樹儲存索引來說,儲存的索引資料會少,就會增加IO次數,同時減少IO量,並且B樹沒有B+樹的葉子節點的左右指標,範圍查詢的效率會更低一點
所以基於此,mysql選擇了B+樹作為索引

1.2 mysql 索引型別

mysql 的索引主要分為普通索引、唯一索引、主鍵索引、組合索引、全文索引等
又或者可以分為單列索引和組合索引,普通,唯一和主鍵都是屬於單列索引的
普通索引沒有任何限制、唯一索引要求唯一,但是允許空值,主鍵索引要求唯一不允許空值
組合索引就是多個欄位建立的索引,遵循最左匹配原則

從儲存角度來說,索引又分為聚簇索引和非聚簇索引, innodb 的索引就是聚簇索引,myisam 就是非聚簇索引
聚簇索引,索引和資料存放在一起,非聚簇索引,索引和資料分開存放,索引執向資料地址
聚簇索引的葉子節點包含有主鍵、事務id、回滾指標、以及餘下的列,聚簇索引的查詢比非聚簇索引快,
非聚簇索引查詢的時候,需要先查詢一遍索引檔案,得到索引後在根據索引查詢對應的資料,二聚簇索引的葉子節點直接指向需要查詢的資料行

1.3 myisam 為什麼比innodb 樹、查詢快

myisam 的查詢比innodb 快的原因是因為myisam 沒有事務以及併發控制,同時myisam 的索引存放的是資料對應的物理偏移量
可以直接定位到資料,而innodb 的話,存在一個mvcc + 事務,同時如果查詢時沒有索引覆蓋,則還需要進行回表查詢,所以相對來說myisam 的查詢快於innodb 

1.4 索引失效

索引失效的情況有多種,比如組合索引沒有遵循最左匹配原則,關聯查詢時,資料型別不一致,模糊匹配使用了萬用字元,where 使用了函式操作,
in 的資料量過多,表資料過少,is not null 等都會導致索引失效

1.5 為什麼排序和分組建議索引

當資料庫執行分組操作時,需要對資料進行排序和分組,如果分組列有索引,資料庫可以之間利用索引的有序性快速完成排序和分組,而無序對整張表進行排序
並且透過索引可以快速定位到滿足條件的資料範圍,因為索引通常都是經過排序的資料結構,減少了需要掃描的數量,在資料量較大時,可以顯著降低磁碟IO操作

1.6 為什麼要選擇合適的資料型別

1. 可以節省磁碟空間
2. 提高查詢效能,較小的資料型別在處理時通常較快,因為需要操作的資料量更少,可以減少資料傳輸時間,記憶體使用和CPU計算時間,從而提高查詢和更新速度
3. 較小的資料型別可以使索引更加緊湊,在索引結構中能儲存更多的鍵值,從而提高索引效能和減少索引的儲存空間
4. 更小的資料型別能在資料庫緩衝池中儲存更多的行資料,增加快取命中率,減少磁碟IO操作

1.7 執行計劃

執行計劃就是透過mysql提供的一個關鍵字, explain + sql 來檢視這個sql 的具體執行計劃
對查詢結果主要關注幾個重要欄位,如 type、key、rows、等
key 指的是預期索引名稱
rows 預期掃描行數
type 是預期訪問方式, system 最好,只有一條資料, all 最差,進行全表掃描. 
  1. system 只有一條資料
  2. const 透過主鍵或者唯一進行等值匹配
  3. eq_ref 透過主鍵或者唯一進行匹配
  4. range 使用索引進行範圍查詢
  5. index 全索引掃描
  6. all 全表掃描 
此外還有key_len 預期索引欄位長度
filtered 返回結果行數佔掃描行數百分比
extra 關於查詢的額外資訊,是否覆蓋,是否使用了臨時表儲存中間結果等

2. mysql 鎖

2.1 mysql 樂觀鎖和悲觀鎖

樂觀鎖: lock share in mode
悲觀鎖: for update

2.2 mysql 鎖都有哪些

mysql 中的鎖包含有共享鎖,排他鎖,意向共享鎖,意向排他鎖,記錄鎖,間隙鎖,臨鍵鎖等
共享鎖允許其他事務讀取但不允許修改,排他鎖不允許其他事務獲取任何型別的鎖
共享鎖常用語讀操作,排他鎖用於寫操作
意向鎖是表級鎖,用於快速判斷表中的是否有被鎖定的記錄,可以提高加鎖的效率,即當事務需要對錶中的某些行加共享鎖或者排他鎖時,先在表級別上新增相應的意向鎖,
在處理行級鎖時,其他事務可以透過檢視錶級的意向鎖,快速判斷是否有行被鎖定,而無序檢查表中的每一行

間隙鎖和臨鍵鎖,這兩個主要時在可重複讀的隔離級別防止幻讀產生,而對範圍查詢進行鎖定,臨鍵鎖就是間隙鎖+記錄鎖

2.3 間隙鎖和臨鍵鎖

在RR隔離級別下,為了解決幻讀問題,會存在間隙鎖和臨鍵鎖,在刪改之後會產生,如果在併發情況下,存在兩個事務都執行了刪改操作,
就會持有間隙鎖,當insert 時,又要先插入間隙獲取意向鎖,就會導致衝突死鎖.

2.4 mvcc

多版本併發控制,透過讀檢視的不同產生時機以及事務id+undolog 來進行多版本併發控制,
在mvcc 中存在3個隱式欄位, row_id, tax_id 和 undo_id , 主鍵id, 當前事務id, 回滾id,
讀檢視, read view 就是在查詢時生成的檢視,不同的隔離級別其生成時機不同,例如RC每次查詢都會生成,RR是事務的第一次查詢才會生成
透過讀檢視的三個隱式欄位,最小事務ID,活躍事務id列表以及下一個待分配的事務id,和當前事務id進行匹配,以達到可見性演算法,做到多版本併發控制
同時 透過臨鍵鎖+間隙鎖,解決了RR級別下的幻讀問題

2.5 讀檢視可見性演算法

當前事務id 首先和讀檢視最小事務id 比較, 當起小於時,說明當前讀檢視生成時,當前事務已經提交,對其可見
否則判斷當前事務id是否大於下一個待分配的事務id, 當其大於時,說明當前讀檢視生成時,當前事務未提交,對其不可見
否則判斷是否在活躍事務列表中,在的話,說明讀檢視生成時,當前事務尚未提交,對其不可見,否則就是對其可見
當不可見時,如果此條記錄存在回滾ID,則會迭代此回滾id,直到找到對其可見的記錄資訊

3. mysql 主從複製

3.1 mysql 主從複製

mysql 的主從複製,都是透過binlog  完成的
每次在寫入資料的時候,都會生成binlog 日誌儲存到本地磁碟中
從機透過IOThread 去定時訪問binlog 日誌,如果binlog 有變化了,將其拿到從機,放到從機的中繼日誌中
之後開啟一個sqlThread 進行解析執行,保證資料一致

3.2 mysql主從複製延時

主從複製出現延時的情況,主要可能有幾個方面的問題,首先是主庫的寫入壓力過大,或者從庫執行的事務過大,又或者是從庫的硬體效能問題,執行緒配置問題
又或者是主從之間的網路問題
避免這種情況,就要首先對住哭的查詢和寫入進行最佳化,減少大事務的使用,合理建立索引,提升從庫的硬體配置,確保主從之間的網路連線穩定,將大事務拆分為多個較小的事務,
減少從庫複製時間,合理分配從庫的複製執行緒等

3.3 binlog 和redo log 的兩階段提交

確保了在binlog 出現異常後,事務也能透過redo log 恢復對應資料
當傳送一條更新Sql 後,由執行其去執行此sql, 
執行其找到儲存引擎去獲取此sql 對應的行,搜尋此資料,記憶體中存在,之間返回執行器,否則磁碟讀取到記憶體,在返回
執行器拿到資料,根據sql進行改變,得到新資料,呼叫引擎寫入資料。
引擎更新到記憶體中,同時會寫入到redolog 檔案,此時redolog 處於prepare 狀態,即告知執行器可以提交事務
執行器生成操作的binlog, 將其寫入磁碟,呼叫引擎的事務提交介面,同時將redolog 的prepare 改為commit 狀態

4. mysql 事務

4.1 事務的特性

ACID 原則,原子性,隔離性,一致性和永續性
事務的所有操作要麼成功要麼失敗回滾
多個事務之間互不干擾
事務執行前後,其狀態不變
事務提交,修改永久儲存

相關文章