訂閱
糾錯
加入自媒體

MySQL常見的存儲引擎InnoDB、MyISAM有何區(qū)別?

2021-04-27 09:47
拓跋阿秀
關注

41、增加B+樹的路數可以降低樹的高度,那么無限增加樹的路數是不是可以有最優(yōu)的查找效率?

不可以。因為這樣會形成一個有序數組,文件系統(tǒng)和數據庫的索引都是存在硬盤上的,并且如果數據量大的話,不一定能一次性加載到內存中。有序數組沒法一次性加載進內存,這時候B+樹的多路存儲威力就出來了,可以每次加載B+樹的一個結點,然后一步步往下找,

42、說一下數據庫表鎖和行鎖吧表鎖

不會出現死鎖,發(fā)生鎖沖突幾率高,并發(fā)低。

MyISAM在執(zhí)行查詢語句(select)前,會自動給涉及的所有表加讀鎖,在執(zhí)行增刪改操作前,會自動給涉及的表加寫鎖。

MySQL的表級鎖有兩種模式:表共享讀鎖和表獨占寫鎖。

讀鎖會阻塞寫,寫鎖會阻塞讀和寫

對MyISAM表的讀操作,不會阻塞其它進程對同一表的讀請求,但會阻塞對同一表的寫請求。只有當讀鎖釋放后,才會執(zhí)行其它進程的寫操作。對MyISAM表的寫操作,會阻塞其它進程對同一表的讀和寫操作,只有當寫鎖釋放后,才會執(zhí)行其它進程的讀寫操作。

MyISAM不適合做寫為主表的引擎,因為寫鎖后,其它線程不能做任何操作,大量的更新會使查詢很難得到鎖,從而造成永遠阻塞。

行鎖

會出現死鎖,發(fā)生鎖沖突幾率低,并發(fā)高。

在MySQL的InnoDB引擎支持行鎖,與Oracle不同,MySQL的行鎖是通過索引加載的,也就是說,行鎖是加在索引響應的行上的,要是對應的SQL語句沒有走索引,則會全表掃描,行鎖則無法實現,取而代之的是表鎖,此時其它事務無法對當前表進行更新或插入操作。

行鎖的實現需要注意:

行鎖必須有索引才能實現,否則會自動鎖全表,那么就不是行鎖了。兩個事務不能鎖同一個索引。insert,delete,update在事務中都會自動默認加上排它鎖。

行鎖的適用場景:

A用戶消費,service層先查詢該用戶的賬戶余額,若余額足夠,則進行后續(xù)的扣款操作;這種情況查詢的時候應該對該記錄進行加鎖。

否則,B用戶在A用戶查詢后消費前先一步將A用戶賬號上的錢轉走,而此時A用戶已經進行了用戶余額是否足夠的判斷,則可能會出現余額已經不足但卻扣款成功的情況。

為了避免此情況,需要在A用戶操作該記錄的時候進行for update加鎖

43、SQL語法中內連接、自連接、外連接(左、右、全)、交叉連接的區(qū)別分別是什么?

內連接:只有兩個元素表相匹配的才能在結果集中顯示。

外連接:左外連接: 左邊為驅動表,驅動表的數據全部顯示,匹配表的不匹配的不會顯示。

右外連接:右邊為驅動表,驅動表的數據全部顯示,匹配表的不匹配的不會顯示。全外連接:連接的表中不匹配的數據全部會顯示出來。

交叉連接:笛卡爾效應,顯示的結果是鏈接表數的乘積。

44、你知道哪些數據庫結構優(yōu)化的手段?

范式優(yōu)化:比如消除冗余(節(jié)省空間。。)反范式優(yōu)化:比如適當加冗余等(減少join)限定數據的范圍:務必禁止不帶任何限制數據范圍條件的查詢語句。比如:我們當用戶在查詢訂單歷史的時候,我們可以控制在一個月的范圍內。讀/寫分離:經典的數據庫拆分方案,主庫負責寫,從庫負責讀;拆分表:分區(qū)將數據在物理上分隔開,不同分區(qū)的數據可以制定保存在處于不同磁盤上的數據文件里。這樣,當對這個表進行查詢時,只需要在表分區(qū)中進行掃描,而不必進行全表掃描,明顯縮短了查詢時間,另外處于不同磁盤的分區(qū)也將對這個表的數據傳輸分散在不同的磁盤I/O,一個精心設置的分區(qū)可以將數據傳輸對磁盤I/O競爭均勻地分散開。對數據量大的時時表可采取此方法?砂丛伦詣咏ū矸謪^(qū)。

45、數據庫優(yōu)化中有一個比較常用的手段就是把數據表進行拆分,關于拆分數據表你了解哪些?

拆分其實又分垂直拆分和水平拆分

案例:簡單購物系統(tǒng)暫設涉及如下表:

1.產品表(數據量10w,穩(wěn)定)

2.訂單表(數據量200w,且有增長趨勢)

3.用戶表 (數據量100w,且有增長趨勢)

以 MySQL 為例講述下水平拆分和垂直拆分,MySQL能容忍的數量級在百萬靜態(tài)數據可以到千萬

垂直拆分

解決問題:表與表之間的io競爭

不解決問題:單表中數據量增長出現的壓力

方案:把產品表和用戶表放到一個server上 訂單表單獨放到一個server上

水平拆分

解決問題:單表中數據量增長出現的壓力

不解決問題:表與表之間的io爭奪

方案:用戶表 通過性別拆分為男用戶表和女用戶表,訂單表 通過已完成和完成中拆分為已完成訂單和未完成訂單,產品表 未完成訂單放一個server上,已完成訂單表盒男用戶表放一個server上,女用戶表放一個server上(女的愛購物 哈哈)。

46、為什么MySQL索引要使用B+樹,而不是B樹或者紅黑樹?

我們在MySQL中的數據一般是放在磁盤中的,讀取數據的時候肯定會有訪問磁盤的操作,磁盤中有兩個機械運動的部分,分別是盤片旋轉和磁臂移動。盤片旋轉就是我們市面上所提到的多少轉每分鐘,而磁盤移動則是在盤片旋轉到指定位置以后,移動磁臂后開始進行數據的讀寫。那么這就存在一個定位到磁盤中的塊的過程,而定位是磁盤的存取中花費時間比較大的一塊,畢竟機械運動花費的時候要遠遠大于電子運動的時間。當大規(guī)模數據存儲到磁盤中的時候,顯然定位是一個非;ㄙM時間的過程,但是我們可以通過B樹進行優(yōu)化,提高磁盤讀取時定位的效率。

為什么B類樹可以進行優(yōu)化呢?我們可以根據B類樹的特點,構造一個多階的B類樹,然后在盡量多的在結點上存儲相關的信息,保證層數(樹的高度)盡量的少,以便后面我們可以更快的找到信息,磁盤的I/O操作也少一些,而且B類樹是平衡樹,每個結點到葉子結點的高度都是相同,這也保證了每個查詢是穩(wěn)定的。

特別地:只有B-樹和B+樹,這里的B-樹是叫B樹,不是B減樹,沒有B減樹的說法。

47、為什么MySQL索引采用B+樹而不用hash表和B樹?

利用Hash需要把數據全部加載到內存中,如果數據量大,是一件很消耗內存的事,而采用B+樹,是基于按照節(jié)點分段加載,由此減少內存消耗。和業(yè)務場景有段,對于唯一查找(查找一個值),Hash確實更快,但數據庫中經常查詢多條數據,這時候由于B+數據的有序性,與葉子節(jié)點又有鏈表相連,他的查詢效率會比Hash快的多。b+樹的非葉子節(jié)點不保存數據,只保存子樹的臨界值(最大或者最。,所以同樣大小的節(jié)點,b+樹相對于b樹能夠有更多的分支,使得這棵樹更加矮胖,查詢時做的IO操作次數也更少。

48、MySQL中存儲索引用到的數據結構是B+樹,B+樹的查詢時間跟樹的高度有關,是log(n),如果用hash存儲,那么查詢時間是O(1)。既然hash比B+樹更快,為什么MySQL用B+樹來存儲索引呢?

一、從內存角度上說,數據庫中的索引一般是在磁盤上,數據量大的情況可能無法一次性裝入內存,B+樹的設計可以允許數據分批加載。

二、從業(yè)務場景上說,如果只選擇一個數據那確實是hash更快,但是數據庫中經常會選中多條,這時候由于B+樹索引有序,并且又有鏈表相連,它的查詢效率比hash就快很多了。

49、關系型數據庫的四大特性在得不到保障的情況下會怎樣?

ACID,原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)

我們以從A賬戶轉賬50元到B賬戶為例進行說明一下ACID這四大特性。

原子性

原子性是指一個事務是一個不可分割的工作單位,其中的操作要么都做,要么都不做。即要么轉賬成功,要么轉賬失敗,是不存在中間的狀態(tài)!

如果無法保證原子性會怎么樣?

OK,就會出現數據不一致的情形,A賬戶減去50元,而B賬戶增加50元操作失敗。系統(tǒng)將無故丟失50元~

一致性

一致性是指事務執(zhí)行前后,數據處于一種合法的狀態(tài),這種狀態(tài)是語義上的而不是語法上的。那什么是合法的數據狀態(tài)呢?這個狀態(tài)是滿足預定的約束就叫做合法的狀態(tài),再通俗一點,這狀態(tài)是由你自己來定義的。滿足這個狀態(tài),數據就是一致的,不滿足這個狀態(tài),數據就是不一致的!

如果無法保證一致性會怎么樣?例一:A賬戶有200元,轉賬300元出去,此時A賬戶余額為-100元。你自然就發(fā)現了此時數據是不一致的,為什么呢?因為你定義了一個狀態(tài),余額這列必須大于0。例二:A賬戶200元,轉賬50元給B賬戶,A賬戶的錢扣了,但是B賬戶因為各種意外,余額并沒有增加。你也知道此時數據是不一致的,為什么呢?因為你定義了一個狀態(tài),要求A+B的余額必須不變。隔離性

隔離性是指多個事務并發(fā)執(zhí)行的時候,事務內部的操作與其他事務是隔離的,并發(fā)執(zhí)行的各個事務之間不能互相干擾。

如果無法保證隔離性會怎么樣?

假設A賬戶有200元,B賬戶0元。A賬戶往B賬戶轉賬兩次,金額為50元,分別在兩個事務中執(zhí)行。如果無法保證隔離性,A可能就會出現扣款兩次的情形,而B只加款一次,憑空消失了50元,依然出現了數據不一致的情形!

持久性

根據定義,持久性是指事務一旦提交,它對數據庫的改變就應該是永久性的。接下來的其他操作或故障不應該對其有任何影響。

如果無法保證持久性會怎么樣?

在MySQL中,為了解決CPU和磁盤速度不一致問題,MySQL是將磁盤上的數據加載到內存,對內存進行操作,然后再回寫磁盤。好,假設此時宕機了,在內存中修改的數據全部丟失了,持久性就無法保證。

設想一下,系統(tǒng)提示你轉賬成功。但是你發(fā)現金額沒有發(fā)生任何改變,此時數據出現了不合法的數據狀態(tài),我們將這種狀態(tài)認為是數據不一致的情形。

50、數據庫如何保證一致性?

分為兩個層面來說。

從數據庫層面,數據庫通過原子性、隔離性、持久性來保證一致性。也就是說ACID四大特性之中,C(一致性)是目的,A(原子性)、I(隔離性)、D(持久性)是手段,是為了保證一致性,數據庫提供的手段。數據庫必須要實現AID三大特性,才有可能實現一致性。例如,原子性無法保證,顯然一致性也無法保證。從應用層面,通過代碼判斷數據庫數據是否有效,然后決定回滾還是提交數據!

51、數據庫如何保證原子性?

主要是利用 Innodb 的undo log。undo log名為回滾日志,是實現原子性的關鍵,當事務回滾時能夠撤銷所有已經成功執(zhí)行的 SQL語句,他需要記錄你要回滾的相應日志信息。例如

當你delete一條數據的時候,就需要記錄這條數據的信息,回滾的時候,insert這條舊數據當你update一條數據的時候,就需要記錄之前的舊值,回滾的時候,根據舊值執(zhí)行update操作當年insert一條數據的時候,就需要這條記錄的主鍵,回滾的時候,根據主鍵執(zhí)行delete操作

undo log記錄了這些回滾需要的信息,當事務執(zhí)行失敗或調用了rollback,導致事務需要回滾,便可以利用undo log中的信息將數據回滾到修改之前的樣子。

52、數據庫如何保證持久性?

主要是利用Innodb的redo log。重寫日志, 正如之前說的,MySQL是先把磁盤上的數據加載到內存中,在內存中對數據進行修改,再寫回到磁盤上。如果此時突然宕機,內存中的數據就會丟失。怎么解決這個問題?簡單啊,事務提交前直接把數據寫入磁盤就行啊。這么做有什么問題?

只修改一個頁面里的一個字節(jié),就要將整個頁面刷入磁盤,太浪費資源了。畢竟一個頁面16kb大小,你只改其中一點點東西,就要將16kb的內容刷入磁盤,聽著也不合理。畢竟一個事務里的SQL可能牽涉到多個數據頁的修改,而這些數據頁可能不是相鄰的,也就是屬于隨機IO。顯然操作隨機IO,速度會比較慢。

于是,決定采用redo log解決上面的問題。當做數據修改的時候,不僅在內存中操作,還會在redo log中記錄這次操作。當事務提交的時候,會將redo log日志進行刷盤(redo log一部分在內存中,一部分在磁盤上)。當數據庫宕機重啟的時候,會將redo log中的內容恢復到數據庫中,再根據undo log和binlog內容決定回滾數據還是提交數據。

采用redo log的好處?

其實好處就是將redo log進行刷盤比對數據頁刷盤效率高,具體表現如下:

redo log體積小,畢竟只記錄了哪一頁修改了啥,因此體積小,刷盤快。redo log是一直往末尾進行追加,屬于順序IO。效率顯然比隨機IO來的快。結語

你學廢了嗎

image.png

---END---

你好,我是阿秀,畢業(yè)于雙非學校,校招時拿下字節(jié)跳動SP、華為、百度等6個offer,現于抖音部門擔任全棧開發(fā)工程師。

一路走來,很累也很不容易,希望能幫助到更多像我一樣的普通學校的學生,我踩的坑不希望你再踩,我走過的路希望你照著走下來。公眾號后臺回復「寶貝」,送你一個寶貝!

<上一頁  1  2  3  
聲明: 本文由入駐維科號的作者撰寫,觀點僅代表作者本人,不代表OFweek立場。如有侵權或其他問題,請聯系舉報。

發(fā)表評論

0條評論,0人參與

請輸入評論內容...

請輸入評論/評論長度6~500個字

您提交的評論過于頻繁,請輸入驗證碼繼續(xù)

暫無評論

暫無評論

    掃碼關注公眾號
    OFweek人工智能網
    獲取更多精彩內容
    文章糾錯
    x
    *文字標題:
    *糾錯內容:
    聯系郵箱:
    *驗 證 碼:

    粵公網安備 44030502002758號