MySQL基礎知識(6)

恒辉信达發表於2024-11-19

MySQL 遇到過死鎖問題嗎,你是如何解決的?

排查死鎖的步驟:

  • 檢視死鎖日誌show engine innodb status;
  • 找出死鎖Sql;
  • 分析sql加鎖情況;
  • 模擬死鎖案發;
  • 分析死鎖日誌;
  • 分析死鎖結果。

資料庫索引的原理,為什麼要用 B+樹,為什麼不用二叉樹?

可以從幾個維度去看這個問題,查詢是否夠快,效率是否穩定,儲存資料多少,以及查詢磁碟次數,為什麼不是二叉樹,為什麼不是平衡二叉樹,為什麼不是B樹,而偏偏是B+樹呢?

為什麼不是一般二叉樹?
1)當資料量大時,樹的高度會比較高(樹的高度決定著它的IO操作次數,IO操作耗時大),查詢會比較慢。
2)每個磁碟塊(節點/頁)儲存的資料太小(IO本來是耗時操作,每次IO只能讀取到一個關鍵字,顯然不合適),沒有很好的利用操作磁碟IO的資料交換特性,也沒有利用好磁碟IO的預讀能力(空間區域性性原理),從而帶來頻繁的IO操作。

為什麼不是平衡二叉樹呢?
我們知道,在記憶體比在磁碟的資料,查詢效率快得多。如果樹這種資料結構作為索引,那我們每查詢一次資料就需要從磁碟中讀取一個節點,也就是我們說的一個磁碟塊,但是平衡二叉樹可是每個節點只儲存一個鍵值和資料的,如果是B樹,可以儲存更多的節點資料,樹的高度也會降低,因此讀取磁碟的次數就降下來啦,查詢效率就快啦。

那為什麼不是B樹而是B+樹呢?
1)B+Tree範圍查詢,定位min與max之後,中間葉子節點,就是結果集,不用中序回溯。
2)B+Tree磁碟讀寫能力更強(葉子節點不儲存真實資料,因此一個磁碟塊能儲存的關鍵字更多,因此每次載入的關鍵字越多)
3)B+Tree掃表和掃庫能力更強(B-Tree樹需要掃描整顆樹,B+Tree樹只需要掃描葉子節點)

聚集索引與非聚集索引的區別

一個表中只能擁有一個聚集索引,而非聚集索引一個表可以存在多個。
聚集索引,索引中鍵值的邏輯順序決定了表中相應行的物理順序;非聚集索引,索引中索引的邏輯順序與磁碟上行的物理儲存順序不同。
索引是透過二叉樹的資料結構來描述的,我們可以這麼理解聚簇索引:索引的葉節點就是資料節點。而非聚簇索引的葉節點仍然是索引節點,只不過有一個指標指向對應的資料塊。
聚集索引:物理儲存按照索引排序;非聚集索引:物理儲存不按照索引排序;

limit 1000000 載入很慢的話,你是怎麼解決的呢?

方案一:如果id是連續的,可以這樣,返回上次查詢的最大記錄(偏移量),再往下limit

select id,name from employee where id>1000000 limit 10.

方案二:在業務允許的情況下限制頁數:

建議跟業務討論,有沒有必要查這麼後的分頁啦。因為絕大多數使用者都不會往後翻太多頁。

方案三:order by + 索引(id為索引)

select id,name from employee order by id  limit 1000000,10
SELECT a.* FROM employee a, (select id from employee where 條件 LIMIT 1000000,10 ) b where a.id=b.id

方案四:利用延遲關聯或者子查詢最佳化超多分頁場景。(先快速定位需要獲取的id段,然後再關聯)

如何選擇合適的分散式主鍵方案呢?

資料庫自增長序列或欄位。
UUID
雪花演算法
Redis生成ID
利用zookeeper生成唯一ID

在高併發情況下,如何做到安全的修改同一行資料?

要安全的修改同一行資料,就要保證一個執行緒在修改時其它執行緒無法更新這行記錄。一般有悲觀鎖和樂觀鎖兩種方案

使用悲觀鎖
悲觀鎖思想就是,當前執行緒要進來修改資料時,別的執行緒都得拒之門外~ 比如,可以使用select…for update

select * from User where name=‘jay’ for update

以上這條sql語句會鎖定了User表中所有符合檢索條件(name=‘jay’)的記錄。本次事務提交之前,別的執行緒都無法修改這些記錄。

使用樂觀鎖
樂觀鎖思想就是,有執行緒過來,先放過去修改,如果看到別的執行緒沒修改過,就可以修改成功,如果別的執行緒修改過,就修改失敗或者重試。實現方式:樂觀鎖一般會使用版本號機制或CAS演算法實現。

資料庫的樂觀鎖和悲觀鎖

悲觀鎖
悲觀鎖她專一且缺乏安全感了,她的心只屬於當前事務,每時每刻都擔心著它心愛的資料可能被別的事務修改,所以一個事務擁有(獲得)悲觀鎖後,其他任何事務都不能對資料進行修改啦,只能等待鎖被釋放才可以執行。

樂觀鎖
樂觀鎖的“樂觀情緒”體現在,它認為資料的變動不會太頻繁。因此,它允許多個事務同時對資料進行變動。實現方式:樂觀鎖一般會使用版本號機制或CAS演算法實現。

SQL最佳化的一般步驟是什麼,怎麼看執行計劃(explain),如何理解其中各個欄位的含義?

將explain加在需要檢視的sql語句前面然後執行
如:explain select * from user;

id:
查詢中 SELECT 的識別符號。如果你的查詢包含子查詢或 UNION,MySQL 會為每個 SELECT 語句分配一個唯一的 ID。
對於簡單查詢,通常只有一個 SELECT,其 id 為 1。
對於複雜的查詢,子查詢的 id 會遞增。

select_type:
查詢的型別,表示這個 SELECT 語句是簡單查詢、複雜查詢的一部分,還是 UNION 的一部分等。
常見的值有:SIMPLE(簡單 SELECT,不使用 UNION 或子查詢)、PRIMARY(查詢中最外層的 SELECT)、UNION(UNION 中的第二個或後續的 SELECT 語句)、DEPENDENT UNION(UNION 中的第二個或後續的 SELECT,依賴於外部查詢)、SUBQUERY(子查詢中的第一個 SELECT)、DEPENDENT SUBQUERY(子查詢,依賴於外部查詢)等。

table:
顯示這一行查詢涉及哪個表。

partitions:
匹配查詢的分割槽。如果表是分割槽表,這裡會顯示哪些分割槽被查詢命中。

type:
連線型別或訪問型別,表示 MySQL 在找到所需行時如何查詢表中的資料。常見的型別包括:ALL(全表掃描)、index(全索引掃描)、range(索引範圍掃描)、ref(非唯一性索引掃描)、eq_ref(唯一性索引掃描,對於每個索引鍵,表中最多隻有一條匹配行)、const/system(表中最多有一個匹配行,例如主鍵或唯一索引掃描)等。
type 列的值越優(例如 eq_ref、const > ref > range > index > ALL),查詢效能越好。

possible_keys:
顯示查詢中可能使用的索引。

key:
實際使用的索引。如果沒有使用索引,則為 NULL。

key_len:
使用的索引的長度。在一些情況下,不是索引的全部部分都會被使用。

ref:
顯示索引的哪一列或常量被用於查詢值。

rows:
MySQL 估計為了找到所需的行而要檢查的行數。這是一個估計值,並不總是完全準確,但在最佳化查詢時很有參考價值。

filtered:
表示返回結果的行佔開始查詢行的百分比。

Extra:
包含不適合在其他列中顯示的額外資訊。例如:是否使用了檔案排序(Using filesort)、是否使用了臨時表(Using temporary)等。
常見的值包括:

Using where:表示儲存引擎在返回結果前應用了 WHERE 條件。
Using temporary:表示 MySQL 需要建立一個臨時表來儲存結果。
Using filesort:表示 MySQL 需要對資料進行額外的排序操作,不能透過索引順序獲得結果。
No tables used:沒有使用表(例如,查詢中只包含常量)

select for update有什麼含義,會鎖表還是鎖行還是其他?

select for update 含義

select查詢語句是不會加鎖的,但是select for update除了有查詢的作用外,還會加鎖呢,而且它是悲觀鎖哦。至於加了是行鎖還是表鎖,這就要看是不是用了索引/主鍵啦。 沒用索引/主鍵的話就是表鎖,否則就是是行鎖。

如果某個表有近千萬資料,CRUD比較慢,如何最佳化?

分庫分表
某個表有近千萬資料,可以考慮最佳化表結構,分表(水平分表,垂直分表),當然,你這樣回答,需要準備好面試官問你的分庫分表相關問題呀,如

分表方案(水平分表,垂直分表,切分規則hash等)
分庫分表中介軟體(Mycat,sharding-jdbc等)
分庫分表一些問題(事務問題?跨節點Join的問題)
解決方案(分散式事務等)
索引最佳化
除了分庫分表,最佳化表結構,當然還有所以索引最佳化等方案~

如何寫sql能夠有效的使用到複合索引?

複合索引,也叫組合索引,使用者可以在多個列上建立索引,這種索引叫做複合索引。

當我們建立一個組合索引的時候,如(k1,k2,k3),相當於建立了(k1)、(k1,k2)和(k1,k2,k3)三個索引,這就是最左匹配原則。

select * from table where k1=A AND k2=B AND k3=D

有關於複合索引,我們需要關注查詢Sql條件的順序,確保最左匹配原則有效,同時可以刪除不必要的冗餘索引。