一、數據庫類型
常用的關系型數據庫
-
Oracle:功能強大,主要缺點就是貴
-
MySQL:互聯網行業中最流行的數據庫,免費。關系數據庫場景中的功能 MySQL 都能很好的滿足
-
MariaDB:MySQL 的分支,由開源社區維護,被看作 MySQL 的替代品,在擴展功能、存儲引擎上有非常好的改進
-
PostgreSQL:也叫 PGSQL,類似於 Oracle 的多進程框架,可以支持高並發的應用場景,幾乎支持所有的 SQL 標准。適合嚴格的企業應用場景,而 MySQL 更適合業務邏輯相對簡單、數據可靠性要求較低的互聯網場景。
NoSQL數據庫(非關系型數據庫)
-
Redis:提供了持久化能力,支持多種數據類型。適用於數據變化快且數據大小可預測的場景。
-
MongoDB:基於分布式文件存儲的數據庫,將數據存儲為一個文檔,數據結構由鍵值對組成。比較適合表結構不明確,且數據結構可能不斷變化的場景,不適合有事務和復雜查詢的場景。
-
HBase:建立在 HDFS,也就是 Hadoop 文件系統之上的分布式面向列的數據庫。類似於谷歌的大表設計,可以提供快速隨機訪問海量結構化數據。在表中它由行排序,一個表有多個列族以及每一個列族可以有任意數量的列。 HBase 依賴 HDFS 可以實現海量數據的可靠存儲,適用於數據量大,寫多讀少,不需要復雜查詢的場景。
-
Cassandra:高可靠的大規模分布式存儲系統。支持分布式的結構化 Key-value 存儲,以高可用性為主要目標。適合寫多的場景,適合做一些簡單查詢,不適合用來做數據分析統計。
-
Pika:可持久化的大容量類 Redis 存儲服務, 兼容五種主要數據結構的大部分命令。使用磁盤存儲,主要解決 Redis 大容量存儲的成本問題。
NewSQL數據庫(新一代關系型數據庫)
-
TiDB:開源的分布式關系數據庫,幾乎完全兼容 MySQL,能夠支持水平彈性擴展、ACID 事務、標准 SQL、MySQL 語法和 MySQL 協議,具有數據強一致的高可用特性。既適合在線事務處理,也適合在線分析處理。
-
OceanBase:OceanBase 是螞蟻金服的數據庫,可以滿足金融級的可靠性和數據一致性要求的數據庫系統。比較適合事務、並且數據量比較大的情況。不過目前OB已經商業化,不再開源。
二、數據庫范式
前關系數據庫有六種范式:第一范式、第二范式、第三范式、巴斯-科德范式(BCNF)、第四范式和第五范式。范式級別越高對數據表的要求越嚴格。
-
第一范式要求最低,只要求表中字段不可用在拆分。
-
第二范式在第一范式的基礎上要求每條記錄由主鍵唯一區分,記錄中所有屬性都依賴於主鍵。
-
第三范式在第二范式的基礎上,要求所有屬性必須直接依賴主鍵,不允許間接依賴。
-
一般說來,數據庫只需滿足第三范式就可以了。
三、數據庫事務
1. 事務的特性
數據庫事務的特性是面試時考察頻率非常高的題目,共4個特性:
-
原子性:事務由原子的操作序列組成,所有操作要么全部成功,要么全部失敗回滾。
-
一致性:事務的執行不能破壞數據庫數據的完整性和一致性,一個事務在執行之前和執行之后,數據庫都必須處以一致性狀態。比如在做多表操作時,多個表要么都是事務后新的值,要么都是事務前的舊值。
-
隔離性:多個用戶並發訪問數據庫時,數據庫為每個用戶執行的事務,不能被其他事務的操作所干擾,多個並發事務之間要相互隔離。事務的隔離級別我們稍后介紹。
-
持久性:一個事務一旦提交並執行成功,那么對數據庫中數據的改變就是永久性的,即便是在數據庫系統遇到故障的情況下也不會丟失提交事務的操作。
2. 事務並發問題
-
臟讀:臟讀是指在一個事務處理過程里讀取了另一個未提交的事務中的數據,例如,賬戶 A 轉帳給賬戶 B 人民幣 500 元,B 余額增加后但事務還沒有提交完成,此時如果另外的請求中獲取的是 B 增加后的余額,這就發生了臟讀,因為事務如果失敗回滾時,B 的余額就不應該增加。
-
不可重復讀:不可重復讀是指對於數據庫中某個數據,一個事務范圍內多次查詢返回了不同的數據值,這是由於在多次查詢之間,有其他事務修改了數據並進行了提交。
-
幻讀:是指一個事務中執行兩次完全相同的查詢時,第二次查詢所返回的結果集跟第一個查詢不相同。與不可重復讀的區別在於,不可重復讀是對同一條記錄,兩次讀取的值不同。而幻讀是記錄的增加或刪除,導致兩次相同條件獲取的結果記錄數不同。
3. 事務的四種隔離級別
可以用於解決上述幾種並發問題。下面4種隔離級別由低到高。
-
級別1——讀未提交:可以讀取到其他事務未提交的內容,這是最低的隔離級別,這個隔離級別下,臟讀、不可重復讀、幻讀都有可能發生。
-
級別2——讀已提交:只能讀取到其他事務已經提交的數據。這個隔離級別可以解決臟讀問題。
-
級別3——可重復讀:可以保證整個事務過程中,對同數據的多次讀取結果是相同的。這個級別可以解決臟讀和不可重復讀的問題。MySQL默認的隔離級別就是可重復讀。
-
級別4——串行化:最高的隔離級別,所有事務操作都依次順序執行。這個級別會導致並發度下降,性能最差。不過這個級別可以解決前面提到的所有並發問題。
4. 事務分類
事務共分為共分5大類:
-
扁平化事務:在扁平事務中,所有的操作都在同一層次,是平時使用最多的一種事務。它的主要限制是不能提交或者回滾事務的某一部分,要么都成功,要么都回滾。
-
帶保存點的扁平事務:為了解決第一種事務的弊端,就有了第二種帶保存點的扁平事務。它允許事務在執行過程中回滾到較早的狀態,而不是全部回滾。通過在事務中插入保存點,當操作失敗后,可以選擇回滾到最近的保存點處。
-
鏈事務:可以看做是第二種事務的變種。它在事務提交時,會將必要的上下文隱式傳遞給下一個事務,當事務失敗時就可以回滾到最近的事務。不過,鏈事務只能回滾到最近的保存點,而帶保存點的扁平化事務是可以回滾到任意的保存點。
-
嵌套事務:由頂層事務和子事務構成,類似於樹的結構。一般頂層事務負責邏輯管理,子事務負責具體的工作,子事務可以提交,但真正提交要等到父事務提交,如果上層事務回滾,那么所有的子事務都會回滾。
-
分布式事務:是指分布式環境中的扁平化事務。一般有四種分布式事務的方案
- XA協議:是保證強一致性的剛性事務。實現方式有兩段式提交和三段式提交。兩段式提交需要有一個事務協調者來保證所有的事務參與者都完成了第一階段的准備工作。如果協調者收到所有參與者都准備好的消息,就會通知所有的事務執行第二階段提交。一般場景下兩段式提交已經能夠很好得解決分布式事務了,然而兩階段在即使只有一個進程發生故障時,也會導致整個系統存在較長時間的阻塞。三段式提交通過增加Pre-commit階段來減少前面提到的系統阻塞的時間。三段式提交很少在實際中使用,簡單了解就可以了。
- TCC:是滿足最終一致性的柔性事務方案。TCC采用補償機制,核心思想是對每個操作,都要注冊對應的確認和補償操作。它分為三個階段:Try階段主要對業務系統進行檢測及資源預留;Confirm階段對業務系統做確認提交。Cancel階段是在業務執行錯誤,執行回滾,釋放預留的資源。
- 消息事務:第三種方案是消息一致性方案。基本思路是將本地操作和發送消息放在一個事務中,保證本地操作和消息發送要么都成功要么都失敗。下游應用訂閱消息,收到消息后執行對應操作。
- GTS/Fescar:阿里雲中的全局事務服務GTS,對應的開源版本是Fescar。Fescar基於兩段式提交進行改良,剝離了分布式事務方案對數據庫在協議支持上的要求。使用Fescar的前提是分支事務中涉及的資源,必須是支持ACID事務的關系型數據庫。分支的提交和回滾機制,都依賴於本地事務來保障。 Fescar的實現目前還存在一些局限,比如事務隔離級別最高支持到讀已提交級別。
MySQL 數據庫知識點
1. MySQL 的數據類型
2. 常用的 SQL 語句
3. MySQL 主要的存儲引擎
- MyISAM——MySQL 官方提供的存儲引擎,其特點是支持全文索引,查詢效率比較高,缺點是不支持事務、使用表級鎖。
- InnoDB ——MySQL 在5.5版本后將 InnoDB 作為默認存儲引擎,特點是支持 ACID 事務、支持外鍵、支持行級鎖提高了並發效率。
- TokuDB ——第三方開發的開源存儲引擎,有非常快的寫速度,支持數據的壓縮存儲、可以在線添加索引而不影響讀寫操作,但是因為壓縮的原因,TokuDB 非常適合訪問頻率不高的數據或歷史數據歸檔,不適合大量讀取的場景。
4. MySQL 中的鎖
MyIASAM使用表級鎖,InnoDB使用行級鎖。
- 表鎖開銷小,加鎖快,不會出現死鎖;但是鎖的粒度大,發生鎖沖突的概率高,並發訪問效率比較低。
- 行級鎖開銷大,加鎖慢,有可能會出現死鎖,不過因為鎖定粒度最小,發生鎖沖突的概率低,並發訪問效率比較高。
-
共享鎖也就是讀鎖,其他事務可以讀,但不能寫。MySQL可以通過Lock In Share Mode語句顯示使用共享鎖。
-
排他鎖就是寫鎖,其他事務不能讀取,也不能寫。對於Update、Delete和INSERT語句,InnoDB會自動給涉及的數據集加排他鎖,或者使用select for update顯示使用排他鎖。
5. 索引
6. MySQL 的存儲過程與函數
存儲過程和函數都可以避免開發人員重復編寫相同的 SQL 語句,並且存儲過程和函數都是在 MySQL 服務器中執行的,可以減少客戶端和服務器端的數據傳輸。
存儲過程能夠實現更復雜的功能,而函數一般用來實現針對性比較強的功能,例如特殊策略求和等。存儲過程可以執行包括修改表等一系列數據庫操作,而用戶定義函數不能用於執行修改全局數據庫狀態的操作。
存儲過程一般是作為一個獨立的部分來執行,而函數可以作為查詢語句的一個部分來調用。SQL語句中不能使用存儲過程,但可以使用函數。
不過存儲過程一般與數據庫實現綁定,使用存儲過程會降低程序的可移植性,應謹慎使用。
7. MySQL 的其他特性
MySQL8.0有一些新特性
- 默認字符集格式改為了 UTF8;
- 增加了隱藏索引的功能,隱藏后的索引不會被查詢優化器使用,可以使用這個特性用於性能調試;
- 支持了通用表表達式,使復雜查詢中的嵌入表語句更加清晰;
- 新增了窗口函數的概念,它可以用來實現新的查詢方式。窗口函數與 SUM、COUNT等集合函數類似,但不會將多行查詢結果合並,而是將結果放在多行中。即窗口函數不需要GROUP BY。
8. MySQL 調優
一般MySQL調優有4個緯度:
-
針對數據庫設計、表結構設計以及索引設置緯度進行的優化;
-
對業務中使用的 SQL 語句進行優化,例如調整 Where 查詢條件;
-
對 MySQL 服務的配置進行優化,例如對鏈接數的管理,對索引緩存、查詢緩存、排序緩存等各種緩存大小進行優化;
-
對硬件設備和操作系統設置進行優化,例如調整操作系統參數、禁用 Swap、增加內存、升級固態硬盤等等。
這四個緯度從優化的成本角度來講,從上到下優化成本逐漸升高;從優化效果角度來看,從下到上優化的效果更高。
對於研發人員來說,前兩個緯度與業務息息相關,因此需要重點掌握,后兩個緯度更適合 DBA,簡單了解就好。
表結構和索引的優化原則
- 第1個原則:要在設計表結構時,考慮數據庫的水平與垂直擴展能力,提前規划好未來1年的數據量、讀寫量的增長,規划好分庫分表方案。比如設計用戶信息表,預計1年后用戶數據10億條,寫QPS約5000,讀QPS30000,可以設計按UID緯度進行散列,分為4個庫每個庫32張表,單表數據量控制在KW級別;
- 第2個原則:要為字段選擇合適的數據類型,在保留擴展能力的前提下,優先選用較小的數據結構。例如保存年齡的字段,要使用TINYINT而不要使用INT;
- 第3個原則:可以將字段多的表分解成多個表,必要時增加中間表進行關聯。假如一張表有4、50個字段顯然不是一個好的設計;
- 第4個原則:是設計關系數據庫時需要滿足第三范式,但為了滿足第三范式,我們可能會拆分出多張表。而在進行查詢時需要對多張表進行關聯查詢,有時為了提高查詢效率,會降低范式的要求,在表中保存一定的冗余信息,也叫做反范式。但要注意反范式一定要適度;
- 第5個原則:要擅用索引,比如為經常作為查詢條件的字段創建索引、創建聯合索引時要根據最左原則考慮索引的復用能力,不要重復創建索引;要為保證數據不能重復的字段創建唯一索引等等。不過要注意索引對插入、更新等寫操作是有代價的,不要濫用索引。比如像性別這樣唯一很差的字段就不適合建立索引;
- 第6個原則:列字段盡量設置為Not Null,MySQL難以對使用Null的列進行查詢優化,允許Null會使索引、索引統計和值更加復雜。允許Null值的列需要更多的存儲空間,還需要MySQL內部進行特殊處理。
SQL 語句優化原則
- 第1個原則:要找的最需要優化的SQL語句。要么是使用最頻繁的語句,要么是優化后提高最明顯的語句,可以通過查詢MySQL的慢查詢日志來發現需要進行優化的SQL語句;
- 第2個原則:要學會利用MySQL提供的分析工具。例如使用Explain來分析語句的執行計划,看看是否使用了索引,使用了哪個索引,掃描了多少記錄,是否使用文件排序等等。或者利用Profile命令來分析某個語句執行過程中各個分步的耗時;
- 第3個原則:要注意使用查詢語句是要避免使用Select *,而是應該指定具體需要獲取的字段。原因一是可以避免查詢出不需要使用的字段,二是可以避免查詢列字段的元信息;
- 第4個原則:是盡量使用Prepared Statements,一個是性能更好,另一個是可以防止SQL注入;
- 第5個原則:是盡量使用索引掃描來進行排序,也就是盡量在有索引的字段上進行排序操作。面試考
總結
敲黑板
1.必須了解數據庫的基本原理、使用場景以及常用隊列、數據庫的特點。MySQL提供了多種引擎可以支持事務型與非事務型的關系對象庫服務等等。
2.要深刻理解數據庫事務的ACID特性,了解並發事務可能導致的並發問題和不同的數據庫隔離級別如何解決這些並發問題。
3.要掌握常用的MySQL語句,比如WHERE條件查詢語句、JOIN關聯語句、ORDER BY排序語句等等。還要熟悉常用的自帶函數,例如SUM、COUNT等等。
4.要了解MySQL數據庫不同引擎的特點及不同類型的索引實現。比如最長使用的InnoDB非常擅長事務處理,MyISAM比較適合非事務的簡單查詢場景。比如知道MySQL的唯一索引、聯合索引、全文索引等不同索引類型,以及最長使用等B+樹索引實現等等。
面試加分項
加分項
1.要了解新特性,例如MySQL8.0中提供了窗口函數來支持新的查詢方式;支持通用表表達式,使復雜查詢中的嵌入表語句更加清晰等等。
2.要知道數據庫表設計原則,如果有過線上業務數據庫的設計經驗就更好了,你能夠知道如何對容量進行評估,也知道適當分庫分表來保證未來服務的可擴展性,這會對面試起到積極的影響。
3.最好有過數據庫調優經驗,例如明明建立了索引的語句,但是查詢效率還是很慢,通過Explain分析發現表中有多個索引,MySQL的優化器選用了錯誤的索引,導致查詢效率偏低,然后通過在SQL語句中使用Use Index來指定索引解決。