数据库-常见面试题汇总
目錄
SQL語句
內(nèi)外連接的區(qū)別?
SQL語言包括哪些類型?
SQL 約束有哪幾種?
視圖
視圖的作用,視圖可以更改么?
事務(wù)和鎖
什么是事務(wù)和鎖?
事務(wù)的四大特性實(shí)現(xiàn)原理?
事務(wù)的隔離級(jí)別?
臟讀、不可重復(fù)讀、幻讀?
鎖的分類
悲觀鎖有哪些劣勢(shì)?
索引
索引的缺點(diǎn)?
索引的分類?
聚簇索引的實(shí)現(xiàn)原理,為什么使用聚簇索引?
性能優(yōu)化
數(shù)據(jù)庫如何優(yōu)化性能?
索引如何優(yōu)化?
如何優(yōu)化關(guān)聯(lián)查詢
為什么要分庫分表?
分庫分表有幾種方法?
如何保證多個(gè)主從數(shù)據(jù)庫之間的數(shù)據(jù)一致?
數(shù)據(jù)庫并發(fā)造成的讀問題有哪些?如何解決?
范式
數(shù)據(jù)庫的三范式是什么?
日志
數(shù)據(jù)庫日志分為哪幾種?
Mysql
主鍵 超鍵 候選鍵 外鍵
drop,delete與truncate的區(qū)別
MySQL中 in 和 exists 區(qū)別
Mysql默認(rèn)的事務(wù)隔離級(jí)別是什么?
聊聊MySQL索引的發(fā)展過程?從沒有索引、hash、二叉排序樹、AVL樹、B樹、B+樹 聊
MySQL 支持哪些存儲(chǔ)引擎?
Mysql的Innodb引擎如何實(shí)現(xiàn)MVCC的?
MyISAM和InnoDB
MySQL 執(zhí)行查詢的過程
什么是MySQL的 binlog?
Redis
Redis是什么?簡(jiǎn)述它的優(yōu)缺點(diǎn)?
Redis的常用場(chǎng)景有哪些?
Redis的數(shù)據(jù)類型有哪些?
Redis會(huì)存在線程切換的問題么?
談?wù)凴edis單線程模型和IO多路復(fù)用?
Redis的大Key的問題,如果有個(gè)Value的大小是2M,會(huì)有什么問題么?最大支持的Value大小是多少?
什么是緩存預(yù)熱?
Redis中緩存穿透的問題,以及解決的方法?
還有其它解決緩存穿透的方法么?布隆過濾器有了解過么?
Redis中大面積的緩存失效(緩存雪崩),然后請(qǐng)求全部打到數(shù)據(jù)庫,有什么解決方法?
如果出現(xiàn)一些熱點(diǎn)數(shù)據(jù),比如明星之間的八卦,造成大量的吃瓜用戶涌入后臺(tái),但是服務(wù)器還沒有緩存對(duì)應(yīng)的數(shù)據(jù)(緩存擊穿),這樣可能造成數(shù)據(jù)庫宕機(jī),如何避免這樣的情況?
談?wù)凴edis主從復(fù)制原理?
索引為什么用B樹?
哨兵模式的優(yōu)缺點(diǎn)?
SQL語句
內(nèi)外連接的區(qū)別?
內(nèi)連接是保證兩個(gè)表中所有的行都要滿足連接條件,而外連接則不然。
在外連接中,某些不滿條件的列也會(huì)顯示出來,也就是說,只限制其中一個(gè)表的行,而不限制另一個(gè)表的行。分左連接、右連接、全連接三種。
SQL語言包括哪些類型?
數(shù)據(jù)定義:Create Table,Alter Table,Drop/Truncate?Table, Create/Drop Index
數(shù)據(jù)操縱:Select ,Insert,Update,Delete
數(shù)據(jù)控制:Grant,Revoke
SQL 約束有哪幾種?
- NOT NULL: 用于控制字段的內(nèi)容一定不能為空(NULL)。
- UNIQUE: 控件字段內(nèi)容不能重復(fù),一個(gè)表允許有多個(gè) Unique 約束。
- PRIMARY KEY: 也是用于控件字段內(nèi)容不能重復(fù),但它在一個(gè)表只允許出現(xiàn)一個(gè)。
- FOREIGN KEY: 用于預(yù)防破壞表之間連接的動(dòng)作,也能防止非法數(shù)據(jù)插入外鍵列,因?yàn)樗仨毷撬赶虻哪莻€(gè)表中的值之一。
- CHECK: 用于控制字段的值范圍。
視圖
視圖的作用,視圖可以更改么?
- 創(chuàng)建視圖: create view xxx as xxx
- 視圖是虛擬的表,與包含數(shù)據(jù)的表不一樣,視圖只包含使用時(shí)動(dòng)態(tài)檢索數(shù)據(jù)的查詢,不包含任何列或數(shù)據(jù);
- 使用視圖可以簡(jiǎn)化復(fù)雜的sql操作,隱藏具體的細(xì)節(jié),保護(hù)數(shù)據(jù);
- 視圖創(chuàng)建后,可以使用與表相同的方式利用它們;
- 視圖不能被索引,也不能有關(guān)聯(lián)的觸發(fā)器或默認(rèn)值,如果視圖本身內(nèi)有order by則對(duì)視圖再次order by將被覆蓋。
對(duì)于某些視圖,例如,未使用聯(lián)結(jié)子查詢分組聚集函數(shù)Distinct Union等,是可以對(duì)其更新的,對(duì)視圖的更新將對(duì)基表進(jìn)行更新;但是視圖主要用于簡(jiǎn)化檢索,保護(hù)數(shù)據(jù),并不用于更新,而且大部分視圖都不可以更新。
事務(wù)和鎖
什么是事務(wù)和鎖?
事務(wù)就是被綁定在一起作為一個(gè)邏輯工作單元的SQL語句分組,如果任何一個(gè)語句操作失敗那么整個(gè)操作就被失敗,以后操作就會(huì)回滾到操作前狀態(tài),或者是上一個(gè)節(jié)點(diǎn)。為了確保要么執(zhí)行,要么不執(zhí)行,就可以使用事務(wù)。要將一組語句作為事務(wù)考慮,就需要通過ACID測(cè)試,即原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)。
鎖:在所有的DBMS中,鎖是實(shí)現(xiàn)事務(wù)的關(guān)鍵,鎖可以保證事務(wù)的完整性和并發(fā)性。與現(xiàn)實(shí)生活中鎖一樣,它可以使某些數(shù)據(jù)的擁有者,在某段時(shí)間內(nèi)不能使用某些數(shù)據(jù)或數(shù)據(jù)結(jié)構(gòu)。當(dāng)然鎖還分級(jí)別的。共享鎖(只讀不寫)、排他鎖(可讀可寫)等。
事務(wù)的四大特性實(shí)現(xiàn)原理?
原子性(Atomicity):主要依靠undo.log日志實(shí)現(xiàn),即在事務(wù)失敗時(shí)執(zhí)行回滾。undo.log日志會(huì)記錄事務(wù)執(zhí)行的sql,當(dāng)事務(wù)需要回滾時(shí),通過反向補(bǔ)償回滾數(shù)據(jù)庫狀態(tài)。
一致性(Consistency):就是事務(wù)再執(zhí)行的前和后數(shù)據(jù)庫的狀態(tài)都是正常的,表現(xiàn)為沒有違反數(shù)據(jù)完整性,參照完整性和用戶自定義完整性等等,上面三種特性就是為了保證數(shù)據(jù)庫的有一致性。
隔離性(Isolation):多線程時(shí),多事務(wù)之間互相產(chǎn)生了影響,要避免這個(gè)影響,那就加鎖。mysql的鎖有表鎖,行鎖,間隙鎖等。寫寫操作通過加鎖實(shí)現(xiàn)隔離性,寫讀操作通過MVCC實(shí)現(xiàn)。
持久性(Durability):主要依靠redo.log日志實(shí)現(xiàn)。首先,mysql持久化通過緩存來提高效率,即在select時(shí)先查緩存,再查磁盤;在update時(shí)先更新緩存,再更新磁盤。以減少磁盤io次數(shù),提高效率。但由于緩存斷電就沒了,所以需要redo.log日志。在執(zhí)行修改操作時(shí),sql會(huì)先寫入到redo.log日志,再寫入緩存中。這樣即使斷電,也能保證數(shù)據(jù)不丟失,達(dá)到持久性。采用順序io,即文件追加方式,更快。
事務(wù)的隔離級(jí)別?
- 讀未提交(臟讀)
- 讀已提交(不可重復(fù)讀)
- 可重復(fù)讀(幻讀->間隙鎖解決)
- 序列化讀
臟讀、不可重復(fù)讀、幻讀?
臟讀:A事務(wù)執(zhí)行過程中,B事務(wù)讀取了A事務(wù)的修改。但是由于某些原因,A事務(wù)可能沒有完成提交(讀未提交),發(fā)生RollBack了操作,則B事務(wù)所讀取的數(shù)據(jù)就會(huì)是不正確的。
不可重復(fù)讀:B事務(wù)讀取了兩次數(shù)據(jù),在這兩次的讀取過程中A事務(wù)修改了數(shù)據(jù)(讀已提交),B事務(wù)的這兩次讀取出來的數(shù)據(jù)不一樣。B事務(wù)這種讀取的結(jié)果,即為不可重復(fù)讀。
幻讀:事務(wù)讀取了兩次數(shù)據(jù),在這兩次的讀取過程中A事務(wù)添加了數(shù)據(jù),B事務(wù)的這兩次讀取出來的數(shù)據(jù)不一樣。
鎖的分類
- 從數(shù)據(jù)庫系統(tǒng)角度分為三種:X/排他/互斥鎖、S/共享/讀鎖、U/更新鎖。
- 從程序員角度分為兩種:一種是悲觀鎖,一種樂觀鎖。
- 從級(jí)別角度分為三種:行(級(jí))鎖,表(級(jí))鎖,間隙鎖。
還有其他鎖,見下圖:
圖片來源:技術(shù)面試之:五問樂觀鎖悲觀鎖_嗶哩嗶哩_bilibili
X/排他/互斥鎖
如果一個(gè)事務(wù)對(duì)對(duì)象加了排他鎖,其他事務(wù)就不能再給它加任何鎖了。
S/讀/共享鎖
用于所有的只讀數(shù)據(jù)操作。共享鎖是非獨(dú)占的,允許多個(gè)并發(fā)事務(wù)讀取其鎖定的資源。
更新鎖
在修改操作的初始化階段用來鎖定可能要被修改的資源,這樣可以避免使用共享鎖造成的死鎖現(xiàn)象。
當(dāng)使用共享鎖時(shí),修改數(shù)據(jù)的操作分為兩步:
1. 首先獲得一個(gè)共享鎖,讀取數(shù)據(jù),
2. 然后將共享鎖升級(jí)為排他鎖,再執(zhí)行修改操作。
讀寫鎖
是一種 讀共享,寫?yīng)氄嫉逆i(共享鎖+互斥鎖)。可理解為一本小說有多個(gè)作家和讀者,只能一個(gè)作家在寫,允許一個(gè)作家和多個(gè)讀者使用。
當(dāng)讀寫鎖被加了寫鎖時(shí),其他線程對(duì)該鎖加讀鎖或者寫鎖都會(huì)阻塞。
當(dāng)讀寫鎖被加了讀鎖時(shí),其他線程對(duì)該鎖加寫鎖會(huì)阻塞,加讀鎖會(huì)成功。
悲觀鎖
顧名思義,很悲觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人拿這個(gè)數(shù)據(jù)就會(huì)block(阻塞),直到它拿走鎖。利用事務(wù)的機(jī)制,適用臨界區(qū)有IO操作,代碼復(fù)雜,競(jìng)爭(zhēng)激烈的情況。
樂觀鎖
沒有用到鎖,修改時(shí)認(rèn)為自己可以拿到資源,修改資源的狀態(tài)。是使用CAS來進(jìn)行同步,要修改資源時(shí)進(jìn)行一個(gè)compare再swap的操作。是應(yīng)用層實(shí)現(xiàn)的機(jī)制,適用于并發(fā)寫入少,大多是讀操作的情況。
行(級(jí))鎖
某一行數(shù)據(jù)有多個(gè)修改的,后修改的需要等先修改的提交后再執(zhí)行。
表(級(jí))鎖
一個(gè)原因:索引失效(例如,條件語句使用or連接),由行級(jí)鎖升級(jí)為表鎖。
間隙鎖
條件語句表范圍,例如,x列1-9,數(shù)據(jù)庫中x列有4,6,8,那么在提交前就不能插入5。
間隙鎖可解決幻讀問題:MySQL 間隙鎖解決幻讀問題_Ronin_88的博客-CSDN博客_間隙鎖解決幻讀
悲觀鎖有哪些劣勢(shì)?
索引
索引的缺點(diǎn)?
索引一般比較大,存在磁盤中,占空間而且IO操作多了會(huì)耗時(shí)。
對(duì)表記錄進(jìn)行修改操作時(shí),對(duì)有索引字段需要調(diào)整索引,耗時(shí)。
索引的分類?
- 主鍵索引
- 唯一索引
- 普通索引
- 多列索引
- 空間索引
聚簇索引的實(shí)現(xiàn)原理,為什么使用聚簇索引?
聚簇索引,索引的順序就是數(shù)據(jù)存放的順序,所以,很容易理解,一張數(shù)據(jù)表只能有一個(gè)聚簇索引。
聚簇索引要比非聚簇索引查詢效率高很多,特別是范圍查詢的時(shí)候。
| 列經(jīng)常被分組排序 | ? ?應(yīng) | ? ?應(yīng) |
| 返回某范圍內(nèi)的數(shù)據(jù) | ? ?應(yīng) | ? ? ?不應(yīng) |
| 一個(gè)或極少不同值 | ? ? 不應(yīng) | ? ? 不應(yīng) |
| 小數(shù)目的不同值 | ? ?應(yīng) | ? ? 不應(yīng) |
| 大數(shù)目的不同值 | ? ?不應(yīng) | ? ? 應(yīng) |
| 頻繁更新的列 | ? 不應(yīng) | ? ? 應(yīng) |
| 外鍵列 | ? ?應(yīng) | ? ? 應(yīng) |
| 主鍵列 | ? ?應(yīng) | ? ? 應(yīng) |
| 頻繁修改索引列 | ? 不應(yīng) | ? ? ?應(yīng) |
性能優(yōu)化
數(shù)據(jù)庫如何優(yōu)化性能?
- SQL優(yōu)化
- 加緩存
- 分庫分表
- 讀寫分離
索引如何優(yōu)化?
- 表的主鍵、外鍵必須有索引;
- 經(jīng)常與其他表進(jìn)行連接的表,在連接字段上應(yīng)該建立索引;
- 頻繁進(jìn)行數(shù)據(jù)操作的表,不要建立太多的索引;
如何優(yōu)化關(guān)聯(lián)查詢
- 確定ON或者USING子句中是否有索引。
- 確保GROUP BY和ORDER BY只有一個(gè)表中的列,這樣MySQL才有可能使用索引。
為什么要分庫分表?
分表
單表數(shù)據(jù)量太大,會(huì)極大影響sql執(zhí)行的性能。一般來說,單表到幾百萬條數(shù)據(jù)的時(shí)候,性能就會(huì)相對(duì)差一些了,就得分表了。
分表就是把一個(gè)表的數(shù)據(jù)放到多個(gè)表中,然后查詢的時(shí)候你就查一個(gè)表。例如按照用戶 id 來分表,將一個(gè)用戶的數(shù)據(jù)就放在一個(gè)表中(例如,有10000個(gè)用戶,id從1-10000,分為兩個(gè)表,那么id從1-5000的就放到orders1中,查詢id為2000的用戶的訂單時(shí)就從orders1中查)。然后操作的時(shí)候你對(duì)一個(gè)用戶就操作那個(gè)表就好了。這樣可以控制每個(gè)表的數(shù)據(jù)量在可控的范圍內(nèi),比如每個(gè)表就固定在 200 萬以內(nèi)。
分庫
一個(gè)庫一般最多支撐到并發(fā)量2000,超過就要擴(kuò)容了,一個(gè)健康的單庫并發(fā),最好保持在每秒 1000 左右。可以將一個(gè)庫的數(shù)據(jù)拆分到多個(gè)庫中,訪問的時(shí)候就訪問一個(gè)庫好了。
分庫分表有幾種方法?
- 垂直拆分:把一個(gè)有很多字段的表給拆分成多個(gè)表,或者是多個(gè)庫上去。每個(gè)庫表的結(jié)構(gòu)都不一樣,每個(gè)庫表都包含部分字段。一般來說,會(huì)將較少的訪問頻率很高的字段放到一個(gè)表里去,然后將較多的訪問頻率很低的字段放到另外一個(gè)表里去。
- 水平拆分:把一個(gè)表的數(shù)據(jù)給弄到多個(gè)庫的多個(gè)表里去,但是每個(gè)庫的表結(jié)構(gòu)都一樣,只不過每個(gè)庫表放的數(shù)據(jù)是不同的,所有庫表的數(shù)據(jù)加起來就是全部數(shù)據(jù)。
如何保證多個(gè)主從數(shù)據(jù)庫之間的數(shù)據(jù)一致?
- 基于二進(jìn)制日志復(fù)制(完整復(fù)制、增量復(fù)制)
數(shù)據(jù)庫并發(fā)造成的讀問題有哪些?如何解決?
- 臟讀?? -->?? 讀提交
- 不可重復(fù)讀? --->可重復(fù)讀
- 幻讀 ------>間隙鎖/序列化
范式
數(shù)據(jù)庫的三范式是什么?
- 第一范式:強(qiáng)調(diào)列的原子性,即數(shù)據(jù)庫表的每一列都是不可分割的。
- 第二范式:要求實(shí)體的屬性完全依賴主關(guān)鍵字,不能存在部分依賴。
- 第三范式:任何非主屬性不依賴于其它非主屬性,消除了傳遞依賴。
日志
數(shù)據(jù)庫日志分為哪幾種?
- 通用查詢?nèi)罩?/li>
- 慢查詢?nèi)罩?/li>
- 錯(cuò)誤日志
- 二進(jìn)制日志
Mysql
主鍵 超鍵 候選鍵 外鍵
- 主鍵:數(shù)據(jù)庫表中對(duì)存儲(chǔ)數(shù)據(jù)對(duì)象予以唯一和完整標(biāo)識(shí)的數(shù)據(jù)列或?qū)傩缘慕M合。一個(gè)數(shù)據(jù)列只能有一個(gè)主鍵,且主鍵的取值不能缺失,即不能為空值(Null).
- 超鍵:在關(guān)系中能唯一標(biāo)識(shí)元組的屬性集稱為關(guān)系模式的超鍵。一個(gè)屬性可以作為一個(gè)超鍵,多個(gè)屬性組合在一起也可以作為一個(gè)超鍵。超鍵包含候選鍵和主鍵。
- 候選鍵:是最小超鍵,即沒有冗余元素的超鍵。
- 外鍵:在一個(gè)表中存在的另一個(gè)表的主鍵稱此表的外鍵。
drop,delete與truncate的區(qū)別
drop直接刪掉表,不可回滾,truncate刪除表中所有數(shù)據(jù),或者說截?cái)啾?#xff0c;與drop一樣,不可回滾,再插入時(shí)自增長(zhǎng)id又從1開始,delete刪除表中數(shù)據(jù),可以加where子句,可以回滾。
1.delete語句執(zhí)行刪除的過程是每次從表中刪除一行,并且同時(shí)將該行的刪除操作作為事務(wù)記錄在日志中保存以便進(jìn)行回滾操作。truncate table則一次性地從表中刪除所有的數(shù)據(jù)并不把單獨(dú)的刪除操作記錄記入日志保存,刪除行是不能恢復(fù)的。并且在刪除的過程中不會(huì)激活與表有關(guān)的刪除觸發(fā)器,執(zhí)行速度快。
2.表和索引所占空間:當(dāng)表被truncate后,這個(gè)表和索引所占用的空間會(huì)恢復(fù)到初始大小,而delete操作不會(huì)減少表或索引所占用的空間。drop語句將表所占用的空間全釋放掉。
3.一般而言,drop>truncate>delete
4.應(yīng)用范圍:truncate只能對(duì)table,delete可以是table和view
5.結(jié)構(gòu)和數(shù)據(jù):truncate和delete只刪除數(shù)據(jù),而drop則刪除整個(gè)表(結(jié)構(gòu)和數(shù)據(jù))
6.truncate與不帶where的delete:只刪除數(shù)據(jù),而不刪除表的結(jié)構(gòu)(定義)drop語句將刪除表的結(jié)構(gòu)被依賴的約束(constrain),觸發(fā)器(trigger),索引(index);依賴于該表的存儲(chǔ)過程/函數(shù)將被保留,但其狀態(tài)會(huì)變?yōu)?invalid
MySQL中 in 和 exists 區(qū)別
MySQL中的in語句是把外表和內(nèi)表作hash連接,而exists語句是對(duì)外表作loop循環(huán),每次loop循環(huán)再對(duì)內(nèi)表進(jìn)行查詢。大家一直認(rèn)為exists比in語句的效率要高,這種說法其實(shí)是不準(zhǔn)確的。這個(gè)是要區(qū)分環(huán)境的。
如果查詢的兩個(gè)表大小相當(dāng),那么用in和exists差別不大。 如果兩個(gè)表中一個(gè)較小,一個(gè)是大表,則子查詢表大的用exists,子查詢表小的用in。
not in 和not exists:如果查詢語句使用了not in,那么內(nèi)外表都進(jìn)行全表掃描,沒有用到索引;而not extsts的子查詢依然能用到表上的索引。所以無論那個(gè)表大,用not exists都比not in要快。
Mysql默認(rèn)的事務(wù)隔離級(jí)別是什么?
可重復(fù)讀
聊聊MySQL索引的發(fā)展過程?從沒有索引、hash、二叉排序樹、AVL樹、B樹、B+樹 聊
沒有索引,全遍歷
哈希索引(hash index),基于哈希表實(shí)現(xiàn),只有精確匹配索引所有列的查詢才有效。對(duì)于每一行數(shù)據(jù),存儲(chǔ)引擎都會(huì)對(duì)所有的索引列計(jì)算一個(gè)哈希碼(hash code), ?哈希碼是一個(gè)較小的值,并且不同鍵值的行計(jì)算出來的哈希碼也不一樣。哈希索引將所有的哈希碼存儲(chǔ)在索引中,同時(shí)在哈希表中保存指向每個(gè)數(shù)據(jù)行的指針。Memory引擎默認(rèn)支持哈希索引,如果多個(gè)hash值相同,出現(xiàn)哈希碰撞,那么索引以鏈表方式存儲(chǔ)。
二叉排序樹,理想情況下是二分,可能創(chuàng)建時(shí)比較深,和一條線差不多,性能并不高
AVL樹,解決了二叉排序樹的問題,但是
1、每次都要檢查規(guī)則,再把樹進(jìn)行重新平衡,這個(gè)是非常消耗時(shí)間的
2、數(shù)據(jù)量大的話,紅黑樹的深度會(huì)比較深,樹一旦深就代表著我們讀取磁盤次數(shù)就會(huì)增加
B樹,每個(gè)非葉子節(jié)點(diǎn)由n-1個(gè)key和n個(gè)指針組成,其中d<=n<=2d。每個(gè)葉子節(jié)點(diǎn)最少包含一個(gè)key和兩個(gè)指針,最多包含2d-1個(gè)key和2d個(gè)指針,葉節(jié)點(diǎn)的指針均為null 。從根節(jié)點(diǎn)進(jìn)行二分查找,影響查詢的是樹的高度,使用B樹,樹的高度可以降低,適合單次查詢,N個(gè)key,高度為h,樹的度為d,時(shí)間復(fù)雜度為,。
B+樹,每個(gè)節(jié)點(diǎn)的指針上限為2d而不是2d+1。非葉子節(jié)點(diǎn)不存儲(chǔ)data,只存儲(chǔ)key,葉子節(jié)點(diǎn)不存儲(chǔ)指針。一般B+樹的階數(shù)(樹節(jié)點(diǎn)包含的子節(jié)點(diǎn)數(shù))不會(huì)超過100,這樣一般保證樹的高度在3~5層而已,查詢速度大大的提升,適合遍歷查詢。
MySQL 支持哪些存儲(chǔ)引擎?
MySQL 支持多種存儲(chǔ)引擎,比如 InnoDB,MyISAM,Memory,Archive 等等.在大多數(shù)的情況下,直接選擇使用 InnoDB 引擎都是最合適的,InnoDB 也是 MySQL 的默認(rèn)存儲(chǔ)引擎。
MyISAM 和 InnoDB 的區(qū)別有哪些:
- InnoDB 支持事務(wù),MyISAM 不支持
- InnoDB 支持外鍵,而 MyISAM 不支持
- InnoDB 是聚集索引,數(shù)據(jù)文件是和索引綁在一起的,必須要有主鍵,通過主鍵索引效率很高;MyISAM 是非聚集索引,數(shù)據(jù)文件是分離的,索引保存的是數(shù)據(jù)文件的指針,主鍵索引和輔助索引是獨(dú)立的。
- Innodb 不支持全文索引,而 MyISAM 支持全文索引,查詢效率上 MyISAM 要高;
- InnoDB 不保存表的具體行數(shù),MyISAM 用一個(gè)變量保存了整個(gè)表的行數(shù)。
- MyISAM 采用表級(jí)鎖(table-level locking);InnoDB支持行級(jí)鎖(row-level locking)和表級(jí)鎖,默認(rèn)為行級(jí)鎖。
Mysql的Innodb引擎如何實(shí)現(xiàn)MVCC的?
MVCC全稱是Multi-Version Concurrent Control,即多版本并發(fā)控制,在MVCC協(xié)議下,每個(gè)讀操作會(huì)看到一個(gè)一致性的snapshot(快照),并且可以實(shí)現(xiàn)非阻塞的讀。MVCC允許數(shù)據(jù)具有多個(gè)版本,這個(gè)版本可以是時(shí)間戳或者是全局遞增的事務(wù)ID,在同一個(gè)時(shí)間點(diǎn),不同的事務(wù)看到的數(shù)據(jù)是不同的。
Innodb會(huì)為每一行添加兩個(gè)字段,分別表示該行事務(wù)id(創(chuàng)建版本號(hào))和上個(gè)版本(回滾指針),填入的是事務(wù)的版本號(hào),這個(gè)版本號(hào)隨著事務(wù)的創(chuàng)建不斷遞增。
undo log記錄數(shù)據(jù)各版本修改歷史即事務(wù)鏈
ReadView是讀視圖,包含未提交的事務(wù)ID數(shù)組,數(shù)組中的最小和最大值組成,用于判斷哪些版本可見:不在未提交數(shù)組中且事務(wù)ID<max或者是自己,都可見。
讀已提交:每次都會(huì)生成ReadView。
可重復(fù)讀:一直使用第一次的ReadView。
在repeated read的隔離級(jí)別下,具體各種數(shù)據(jù)庫操作的實(shí)現(xiàn):
- select:該行的創(chuàng)建版本號(hào)小于等于當(dāng)前版本號(hào),用于保證在select操作之前所有的操作已經(jīng)執(zhí)行落地
- insert:將新插入的行的創(chuàng)建版本號(hào)設(shè)置為當(dāng)前系統(tǒng)的版本號(hào)。
- delete:將要?jiǎng)h除的行的刪除版本號(hào)設(shè)置為當(dāng)前系統(tǒng)的版本號(hào)。
- update:不執(zhí)行原地update,而是轉(zhuǎn)換成insert + delete。將舊行的刪除版本號(hào)設(shè)置為當(dāng)前版本號(hào),并將新行insert同時(shí)設(shè)置創(chuàng)建版本號(hào)為當(dāng)前版本號(hào)。
其中,寫操作(insert、delete和update)執(zhí)行時(shí),需要將系統(tǒng)版本號(hào)遞增。
由于舊數(shù)據(jù)并不真正的刪除,所以必須對(duì)這些數(shù)據(jù)進(jìn)行清理,Innodb會(huì)開啟一個(gè)后臺(tái)線程執(zhí)行清理工作,具體的規(guī)則是將刪除版本號(hào)小于當(dāng)前系統(tǒng)版本的行刪除,這個(gè)過程叫做purge。
通過MVCC很好的實(shí)現(xiàn)了事務(wù)的隔離性,可以達(dá)到repeated read級(jí)別,要實(shí)現(xiàn)serializable還必須加鎖。
| 1 | 王五 | 107 | 106 |
| 1 | 李四 | 101 | 100 |
| 1 | 張三 | 100 | 99 |
事務(wù)100已提交,事務(wù)101和107未提交,有一事務(wù)id為105的,查詢當(dāng)前name。ReadView? 101,[101,107],107,107>105,不可讀,101<105但在未提交事務(wù)數(shù)組,不可讀,100<105,且不在未提交事務(wù)數(shù)組,讀取100對(duì)應(yīng)name張三。當(dāng)101提交,在可重復(fù)讀下,仍然為張三,因?yàn)镽eadView沒有變。可以通過間隙鎖(select name for table where id = 1 for update)的方式解決幻讀問題,即讀取id為1所在行數(shù)據(jù),添加間隙鎖,使id為1所在行數(shù)據(jù)不可改變,讀取后才能提交。
MyISAM和InnoDB
MyISAM 適合于一些需要大量查詢的應(yīng)用,但其對(duì)于有大量寫操作并不是很好。甚至你只是需要update一個(gè)字段,整個(gè)表都會(huì)被鎖起來,而別的進(jìn)程,就算是讀進(jìn)程都無法操作直到讀操作完成。另外,MyISAM 對(duì)于 SELECT COUNT(*) 這類的計(jì)算是超快無比的。
InnoDB 的趨勢(shì)會(huì)是一個(gè)非常復(fù)雜的存儲(chǔ)引擎,對(duì)于一些小的應(yīng)用,它會(huì)比 MyISAM 還慢。他是它支持“行鎖” ,于是在寫操作比較多的時(shí)候,會(huì)更優(yōu)秀。并且,他還支持更多的高級(jí)應(yīng)用,比如:事務(wù)。
MySQL 執(zhí)行查詢的過程
什么是MySQL的 binlog?
MySQL的 binlog 是記錄所有數(shù)據(jù)庫表結(jié)構(gòu)變更(例如 CREATE、ALTER TABLE)以及表數(shù)據(jù)修改(INSERT、UPDATE、DELETE)的二進(jìn)制日志。
Redis
Redis是什么?簡(jiǎn)述它的優(yōu)缺點(diǎn)?
Redis本質(zhì)上是一個(gè)Key-Value類型的內(nèi)存數(shù)據(jù)庫,很像Memcached,整個(gè)數(shù)據(jù)庫加載在內(nèi)存當(dāng)中操作,定期通過異步操作把數(shù)據(jù)庫中的數(shù)據(jù)flush到硬盤上進(jìn)行保存。
因?yàn)槭羌儍?nèi)存操作,Redis的性能非常出色,每秒可以處理超過 10萬次讀寫操作,是已知性能最快的Key-Value 數(shù)據(jù)庫。
優(yōu)點(diǎn):
- 讀寫性能極高, Redis能讀的速度是110000次/s,寫的速度是81000次/s。
- 支持?jǐn)?shù)據(jù)持久化,支持AOF和RDB兩種持久化方式。
- 支持事務(wù), Redis的所有操作都是原子性的,意思就是要么成功執(zhí)行要么失敗完全不執(zhí)行。單個(gè)操作是原子性的。多個(gè)操作也支持事務(wù),即原子性,通過MULTI和EXEC指令包起來。
- 數(shù)據(jù)結(jié)構(gòu)豐富,除了支持string類型的value外,還支持hash、set、zset、list等數(shù)據(jù)結(jié)構(gòu)。
- 支持主從復(fù)制,主機(jī)會(huì)自動(dòng)將數(shù)據(jù)同步到從機(jī),可以進(jìn)行讀寫分離。
- 豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過期等特性。
缺點(diǎn):
- 數(shù)據(jù)庫容量受到物理內(nèi)存的限制,不能用作海量數(shù)據(jù)的高性能讀寫,因此Redis適合的場(chǎng)景主要局限在較小數(shù)據(jù)量的高性能操作和運(yùn)算上。
- 主機(jī)宕機(jī),宕機(jī)前有部分?jǐn)?shù)據(jù)未能及時(shí)同步到從機(jī),切換IP后還會(huì)引入數(shù)據(jù)不一致的問題,降低了系統(tǒng)的可用性。
Redis的常用場(chǎng)景有哪些?
1、緩存
緩存現(xiàn)在幾乎是所有中大型網(wǎng)站都在用的必殺技,合理的利用緩存不僅能夠提升網(wǎng)站訪問速度,還能大大降低數(shù)據(jù)庫的壓力。Redis提供了鍵過期功能,也提供了靈活的鍵淘汰策略,所以,現(xiàn)在Redis用在緩存的場(chǎng)合非常多。
2、排行榜
很多網(wǎng)站都有排行榜應(yīng)用的,如京東的月度銷量榜單、商品按時(shí)間的上新排行榜等。Redis提供的有序集合數(shù)據(jù)類構(gòu)能實(shí)現(xiàn)各種復(fù)雜的排行榜應(yīng)用。
3、計(jì)數(shù)器
什么是計(jì)數(shù)器,如電商網(wǎng)站商品的瀏覽量、視頻網(wǎng)站視頻的播放數(shù)等。為了保證數(shù)據(jù)實(shí)時(shí)效,每次瀏覽都得給+1,并發(fā)量高時(shí)如果每次都請(qǐng)求數(shù)據(jù)庫操作無疑是種挑戰(zhàn)和壓力。Redis提供的incr命令來實(shí)現(xiàn)計(jì)數(shù)器功能,內(nèi)存操作,性能非常好,非常適用于這些計(jì)數(shù)場(chǎng)景。
4、分布式會(huì)話
集群模式下,在應(yīng)用不多的情況下一般使用容器自帶的session復(fù)制功能就能滿足,當(dāng)應(yīng)用增多相對(duì)復(fù)雜的系統(tǒng)中,一般都會(huì)搭建以Redis等內(nèi)存數(shù)據(jù)庫為中心的session服務(wù),session不再由容器管理,而是由session服務(wù)及內(nèi)存數(shù)據(jù)庫管理。
5、分布式鎖
在很多互聯(lián)網(wǎng)公司中都使用了分布式技術(shù),分布式技術(shù)帶來的技術(shù)挑戰(zhàn)是對(duì)同一個(gè)資源的并發(fā)訪問,如全局ID、減庫存、秒殺等場(chǎng)景,并發(fā)量不大的場(chǎng)景可以使用數(shù)據(jù)庫的悲觀鎖、樂觀鎖來實(shí)現(xiàn),但在并發(fā)量高的場(chǎng)合中,利用數(shù)據(jù)庫鎖來控制資源的并發(fā)訪問是不太理想的,大大影響了數(shù)據(jù)庫的性能。可以利用Redis的setnx功能來編寫分布式的鎖,如果設(shè)置返回1說明獲取鎖成功,否則獲取鎖失敗,實(shí)際應(yīng)用中要考慮的細(xì)節(jié)要更多。
6、 社交網(wǎng)絡(luò)
點(diǎn)贊、踩、關(guān)注/被關(guān)注、共同好友等是社交網(wǎng)站的基本功能,社交網(wǎng)站的訪問量通常來說比較大,而且傳統(tǒng)的關(guān)系數(shù)據(jù)庫類型不適合存儲(chǔ)這種類型的數(shù)據(jù),Redis提供的哈希、集合等數(shù)據(jù)結(jié)構(gòu)能很方便的的實(shí)現(xiàn)這些功能。如在微博中的共同好友,通過Redis的set能夠很方便得出。
7、最新列表
Redis列表結(jié)構(gòu),LPUSH可以在列表頭部插入一個(gè)內(nèi)容ID作為關(guān)鍵字,LTRIM可用來限制列表的數(shù)量,這樣列表永遠(yuǎn)為N個(gè)ID,無需查詢最新的列表,直接根據(jù)ID去到對(duì)應(yīng)的內(nèi)容頁即可。
8、消息系統(tǒng)
消息隊(duì)列是大型網(wǎng)站必用中間件,如ActiveMQ、RabbitMQ、Kafka等流行的消息隊(duì)列中間件,主要用于業(yè)務(wù)解耦、流量削峰及異步處理實(shí)時(shí)性低的業(yè)務(wù)。Redis提供了發(fā)布/訂閱及阻塞隊(duì)列功能,能實(shí)現(xiàn)一個(gè)簡(jiǎn)單的消息隊(duì)列系統(tǒng)。另外,這個(gè)不能和專業(yè)的消息中間件相比。
Redis的數(shù)據(jù)類型有哪些?
有五種常用數(shù)據(jù)類型:String、Hash、Set、List、SortedSet。以及三種特殊的數(shù)據(jù)類型:Bitmap、HyperLogLog、Geospatial ,其中HyperLogLog、Bitmap的底層都是 String 數(shù)據(jù)類型,Geospatial 的底層是 Sorted Set 數(shù)據(jù)類型。
Redis會(huì)存在線程切換的問題么?
Redis執(zhí)行命令是單線程順序執(zhí)行。多線程部分用來處理網(wǎng)絡(luò)數(shù)據(jù)的讀寫和協(xié)議解析,所以會(huì)進(jìn)行線程切換。
談?wù)凴edis單線程模型和IO多路復(fù)用?
文件事件處理器的四部分:套接字、I/O多路復(fù)用程序、文件事件分派器和事件處理器。?
I/O多路復(fù)用
- I/O: 這是一種處理I/O的高級(jí)模型。
- 多路: 多個(gè)I/O流,多個(gè)Socket連接。
- 復(fù)用:多個(gè)Socket連接共用單個(gè)線程。復(fù)用方式:單個(gè)線程,記錄跟蹤每個(gè)I/O流的狀態(tài),通過開關(guān)控制,每次處理一個(gè)I/O流。
- I/O多路復(fù)用程序,負(fù)責(zé)監(jiān)聽多個(gè)套接字,按照處理順序,將套接字存放在一個(gè)隊(duì)列中。
- 套接字隊(duì)列以有序(sequentially)、同步(synchronously)、每次一個(gè)套接字的方式向文件事件分派器傳送套接字。
- 當(dāng)上一個(gè)套接字產(chǎn)生的事件被處理完畢之后, I/O 多路復(fù)用程序才會(huì)繼續(xù)向文件事件分派器傳送下一個(gè)套接字。
參考:Redis: 單線程模型、I/O多路復(fù)用、影響性能的因素(為什么這么快)、性能與QPS(到底有多快)_韓超的博客 (hanchao5272)-CSDN博客_redis單線程多路復(fù)用
Redis的大Key的問題,如果有個(gè)Value的大小是2M,會(huì)有什么問題么?最大支持的Value大小是多少?
高并發(fā)寫入,影響性能,請(qǐng)求延遲較大。
最大512M
什么是緩存預(yù)熱?
緩存預(yù)熱是指系統(tǒng)上線后,提前將相關(guān)的緩存數(shù)據(jù)加載到緩存系統(tǒng)。避免在用戶請(qǐng)求的時(shí)候,先查詢數(shù)據(jù)庫,然后再將數(shù)據(jù)緩存的問題,用戶直接查詢事先被預(yù)熱的緩存數(shù)據(jù)。
如果不進(jìn)行預(yù)熱,那么Redis初始狀態(tài)數(shù)據(jù)為空,系統(tǒng)上線初期,對(duì)于高并發(fā)的流量,都會(huì)訪問到數(shù)據(jù)庫中, 對(duì)數(shù)據(jù)庫造成流量的壓力。
緩存預(yù)熱解決方案:
- 數(shù)據(jù)量不大的時(shí)候,工程啟動(dòng)的時(shí)候進(jìn)行加載緩存動(dòng)作;
- 數(shù)據(jù)量大的時(shí)候,設(shè)置一個(gè)定時(shí)任務(wù)腳本,進(jìn)行緩存的刷新;
- 數(shù)據(jù)量太大的時(shí)候,優(yōu)先保證熱點(diǎn)數(shù)據(jù)進(jìn)行提前加載到緩存。
Redis中緩存穿透的問題,以及解決的方法?
- 鑒權(quán)與過濾:接口增加用戶鑒權(quán),校驗(yàn)參數(shù),如id<=0時(shí),直接攔截。
- 緩存中設(shè)置為空:從緩存取不到的數(shù)據(jù),在數(shù)據(jù)庫中也沒有取到,這時(shí)也可以將key-value對(duì)寫為key-null,緩存有效時(shí)間可以設(shè)置短點(diǎn),如30秒(設(shè)置太長(zhǎng)會(huì)導(dǎo)致正常情況也沒法使用)。這樣可以防止攻擊用戶反復(fù)用同一個(gè)id暴力攻擊
還有其它解決緩存穿透的方法么?布隆過濾器有了解過么?
有了解過,一個(gè)比較大的哈希表,value是0,1,代表數(shù)據(jù)是否存在。看看b站視頻,再了解下哈希沖突解決。
程序員都必須會(huì)的技術(shù),面試必備【布隆過濾器詳解】,Redis緩存穿透解決方案_嗶哩嗶哩_bilibili
Redis中大面積的緩存失效(緩存雪崩),然后請(qǐng)求全部打到數(shù)據(jù)庫,有什么解決方法?
- redis集群,熱點(diǎn)數(shù)據(jù)均勻分布在不同服務(wù)器
- 限流降級(jí),暫時(shí)關(guān)閉不重要服務(wù),例如,雙11關(guān)閉退款服務(wù)等
- 數(shù)據(jù)預(yù)熱,手動(dòng)觸發(fā)熱點(diǎn),加入緩存,設(shè)置不同過期時(shí)間
如果出現(xiàn)一些熱點(diǎn)數(shù)據(jù),比如明星之間的八卦,造成大量的吃瓜用戶涌入后臺(tái),但是服務(wù)器還沒有緩存對(duì)應(yīng)的數(shù)據(jù)(緩存擊穿),這樣可能造成數(shù)據(jù)庫宕機(jī),如何避免這樣的情況?
- 設(shè)置熱點(diǎn)數(shù)據(jù)永遠(yuǎn)不過期。
- 加互斥鎖,使用分布鎖,保證每個(gè)key同時(shí)只有一個(gè)線程去查詢后端服務(wù),其他線程沒有獲得分布式鎖的權(quán)限,因此只需要等待即可。
談?wù)凴edis主從復(fù)制原理?
Slave啟動(dòng)成功連接到Master后會(huì)發(fā)送一個(gè)sync同步命令Master接到命令,啟動(dòng)后臺(tái)的存盤進(jìn)程,同時(shí)收集所有接收到的用于修改數(shù)據(jù)集命令,在后臺(tái)進(jìn)程執(zhí)行完畢之后,Master將傳送整個(gè)數(shù)據(jù)文件到Slave,并完成一次完全同步。
全量復(fù)制:而Slave服務(wù)在接收到數(shù)據(jù)庫文件數(shù)據(jù)后,將其存盤并加載到內(nèi)存中。
增量復(fù)制:Master繼續(xù)將新的所有收集到的修改命令依次傳給Slave,完成同步但是只要是重新連接Master,一次完全同步(全量復(fù)制)將被自動(dòng)執(zhí)行!
索引為什么用B樹?
減少磁盤IO操作的影響因素
B樹 ???樹內(nèi)的每個(gè)節(jié)點(diǎn)都存儲(chǔ)數(shù)據(jù),葉子節(jié)點(diǎn)之間無指針相鄰,適合單一查詢???
B+樹 ??數(shù)據(jù)只出現(xiàn)在葉子節(jié)點(diǎn),所有葉子節(jié)點(diǎn)增加了一個(gè)鏈指針,適合遍歷查詢
哨兵模式的優(yōu)缺點(diǎn)?
優(yōu)點(diǎn):
??? 哨兵集群,基于主從復(fù)制模式,所有的主從配置優(yōu)點(diǎn),它全有。
??? 主從可以切換,故障可以轉(zhuǎn)移,系統(tǒng)的可用性就會(huì)更好
??? 哨兵模式就是主從模式的升級(jí),手動(dòng)到自動(dòng),更加健壯!
缺點(diǎn):
??? Redis不好在線擴(kuò)容的,集群容量一旦到達(dá)上限,在線擴(kuò)容就十分麻煩!
??? 實(shí)現(xiàn)哨兵模式的配置其實(shí)是很麻煩的,里面有很多選擇!
總結(jié)
以上是生活随笔為你收集整理的数据库-常见面试题汇总的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 人大金仓数据库迁移工具
- 下一篇: 学习jvm,关于MAT an inter