天天看點

一、資料庫的不同類型

一、資料庫的不同類型

1.常用的關系型資料庫

  • **Oracle:**功能強大,主要缺點就是貴
  • **MySQL:**網際網路行業中最流行的資料庫,這不僅僅是因為MySQL的免費。可以說關系資料庫場景中你需要的功能,MySQL都能很好的滿足,後面詳解部分會詳細介紹MySQL的一些知識點
  • **MariaDB:**是MySQL的分支,由開源社群維護,MariaDB雖然被看作MySQL的替代品,但它在擴充功能、存儲引擎上都有非常好的改進
  • **PostgreSQL:**也叫PGSQL,PGSQL類似于Oracle的多程序架構,可以支援高并發的應用場景,PG幾乎支援所有的SQL标準,支援類型相當豐富。PG更加适合嚴格的企業應用場景,而MySQL更适合業務邏輯相對簡單、資料可靠性要求較低的網際網路場景。

2.NoSQL資料庫(非關系型資料庫)

  • **Redis:**提供了持久化能力,支援多種資料類型。Redis适用于資料變化快且資料大小可預測的場景。
  • **MongoDB:**一個基于分布式檔案存儲的資料庫,将資料存儲為一個文檔,資料結構由鍵值對組成。MongoDB比較适合表結構不明确,且資料結構可能不斷變化的場景,不适合有事務和複雜查詢的場景。
  • **HBase:**建立在HDFS,也就是Hadoop檔案系統之上的分布式面向列的資料庫。類似于谷歌的大表設計,HBase可以提供快速随機通路海量結構化資料。在表中它由行排序,一個表有多個列族以及每一個列族可以有任意數量的列。 HBase依賴HDFS可以實作海量資料的可靠存儲,适用于資料量大,寫多讀少,不需要複雜查詢的場景。
  • **Cassandra:**一個高可靠的大規模分布式存儲系統。支援分布式的結構化Key-value存儲,以高可用性為主要目标。适合寫多的場景,适合做一些簡單查詢,不适合用來做資料分析統計。
  • **Pika:**一個可持久化的大容量類Redis存儲服務, 相容五種主要資料結構的大部分指令。Pika使用磁盤存儲,主要解決Redis大容量存儲的成本問題。

3.NewSQL資料庫(新一代關系型資料庫)

  • **TiDB:**開源的分布式關系資料庫,幾乎完全相容MySQL,能夠支援水準彈性擴充、ACID事務、标準SQL、MySQL文法和MySQL協定,具有資料強一緻的高可用特性。既适合線上事務處理,也适合線上分析處理。
  • **OceanBase:**OceanBase是螞蟻金服的資料庫,OB是可以滿足金融級的可靠性和資料一緻性要求的資料庫系統。當你需要使用事務,并且資料量比較大,就比較适合使用OB。不過目前OB已經商業化,不再開源。

二、資料庫的範式

前關系資料庫有六種範式:第一範式、第二範式、第三範式、巴斯-科德範式(BCNF)、第四範式和第五範式。範式級别越高對資料表的要求越嚴格。

  • 第一範式要求最低,隻要求表中字段不可用在拆分。
  • 第二範式在第一範式的基礎上要求每條記錄由主鍵唯一區分,記錄中所有屬性都依賴于主鍵。
  • 第三範式在第二範式的基礎上,要求所有屬性必須直接依賴主鍵,不允許間接依賴。
  • 一般說來,資料庫隻需滿足第三範式就可以了。

詳解知識點一:資料庫事務

知識點

▌1.資料庫事務特性

資料庫的特性是面試時考察頻率非常高的題目,共4個特性:

  • **原子性:**是指事務由原子的操作序列組成,所有操作要麼全部成功,要麼全部失敗復原。
  • **一緻性:**是指事務的執行不能破壞資料庫資料的完整性和一緻性,一個事務在執行之前和執行之後,資料庫都必須處以一緻性狀态。比如在做多表操作時,多個表要麼都是事務後新的值,要麼都是事務前的舊值。
  • **隔離性:**是指多個使用者并發通路資料庫時,資料庫為每個使用者執行的事務,不能被其他事務的操作所幹擾,多個并發事務之間要互相隔離。事務的隔離級别我們稍後介紹。
  • **持久性:**是指一個事務一旦送出并執行成功,那麼對資料庫中資料的改變就是永久性的,即便是在資料庫系統遇到故障的情況下也不會丢失送出事務的操作。

▌2.事物并發問題與隔離級别

  • **髒讀:**髒讀是指在一個事務處理過程裡讀取了另一個未送出的事務中的資料,例如,賬戶A轉帳給B500元,B餘額增加後但事務還沒有送出完成,此時如果另外的請求中擷取的是B增加後的餘額,這就發生了髒讀,因為事務如果失敗復原時,B的餘額就不應該增加。
  • **不可重複讀:**不可重複讀是指對于資料庫中某個資料,一個事務範圍内多次查詢傳回了不同的資料值,這是由于在多次查詢之間,有其他事務修改了資料并進行了送出。
  • **幻讀:**是指一個事務中執行兩次完全相同的查詢時,第二次查詢所傳回的結果集跟第一個查詢不相同。與不可重複讀的差別在于,不可重複讀是對同一條記錄,兩次讀取的值不同。而幻讀是記錄的增加或删除,導緻兩次相同條件擷取的結果記錄數不同。

b:事務的四種隔離級别

可以用于解決這幾種并發問題。如圖右面,由上到下的4種隔離級别由低到高。

  • **級别1讀未送出:**也就是可以讀取到其他事務未送出的内容,這是最低的隔離級别,這個隔離級别下,前面提到的三種并發問題都有可能發生。
  • **級别2讀已送出:**就是隻能讀取到其他事務已經送出的資料。這個隔離級别可以解決髒讀問題。
  • **級别三可重複讀:**可以保證整個事務過程中,對同資料的多次讀取結果是相同的。這個級别可以解決髒讀和不可重複讀的問題。MySQL預設的隔離級别就是可重複讀。
  • **級别四串行化:**這是最高的隔離級别,所有事務操作都依次順序執行。這個級别會導緻并發度下降,性能最差。不過這個級别可以解決前面提到的所有并發問題。

▌3.事務分類

共分5大類:

  • 扁平化事務:在扁平事務中,所有的操作都在同一層次,這也是我們平時使用最多的一種事務。它的主要限制是不能送出或者復原事務的某一部分,要麼都成功,要麼都復原。
  • **帶儲存點的扁平事務:**為了解決第一種事務的弊端,就有了第二種帶儲存點的扁平事務。它允許事務在執行過程中復原到較早的狀态,而不是全部復原。通過在事務中插入儲存點,當操作失敗後,可以選擇復原到最近的儲存點處。
  • **鍊事務:**可以看做是第二種事務的變種。它在事務送出時,會将必要的上下文隐式傳遞給下一個事務,當事務失敗時就可以復原到最近的事務。不過,鍊事務隻能復原到最近的儲存點,而帶儲存點的扁平化事務是可以復原到任意的儲存點。
  • **嵌套事務:**由頂層事務和子事務構成,類似于樹的結構。一般頂層事務負責邏輯管理,子事務負責具體的工作,子事務可以送出,但真正送出要等到父事務送出,如果上層事務復原,那麼所有的子事務都會復原。
  • **分布式事務:**是指分布式環境中的扁平化事務。

其中,常用的分布式事務解決方案共4種

**a.XA協定:**是保證強一緻性的剛性事務。實作方式有兩段式送出和三段式送出。兩段式送出需要有一個事務協調者來保證所有的事務參與者都完成了第一階段的準備工作。如果協調者收到所有參與者都準備好的消息,就會通知所有的事務執行第二階段送出。一般場景下兩段式送出已經能夠很好得解決分布式事務了,然而兩階段在即使隻有一個程序發生故障時,也會導緻整個系統存在較長時間的阻塞。三段式送出通過增加Pre-commit階段來減少前面提到的系統阻塞的時間。三段式送出很少在實際中使用,簡單了解就可以了。

**b.TCC:**是滿足最終一緻性的柔性事務方案。TCC采用補償機制,核心思想是對每個操作,都要注冊對應的确認和補償操作。它分為三個階段:Try階段主要對業務系統進行檢測及資源預留;Confirm階段對業務系統做确認送出。Cancel階段是在業務執行錯誤,執行復原,釋放預留的資源。

**c.消息事務:**第三種方案是消息一緻性方案。基本思路是将本地操作和發送消息放在一個事務中,保證本地操作和消息發送要麼都成功要麼都失敗。下遊應用訂閱消息,收到消息後執行對應操作。

**d.GTS/Fescar:**阿裡雲中的全局事務服務GTS,對應的開源版本是Fescar。Fescar基于兩段式送出進行改良,剝離了分布式事務方案對資料庫在協定支援上的要求。使用Fescar的前提是分支事務中涉及的資源,必須是支援ACID事務的關系型資料庫。分支的送出和復原機制,都依賴于本地事務來保障。 Fescar的實作目前還存在一些局限,比如事務隔離級别最高支援到讀已送出級别。

MySQL資料庫

▌****1.常用SQL語句

需要能手寫常用SQL語句,這裡沒有什麼特殊的技巧,根據如圖列出的語句類型多做一些練習

▌****2.資料類型

要知道MySQL都提供哪些基本都資料類型,不同資料類型占用的空間大小。

▌3.MySQL中主要的存儲引擎

MyISAM是MySQL官方提供的存儲引擎,其特點是支援全文索引,查詢效率比較高,缺點是不支援事務、使用表級鎖。InnoDB在5.5版本後成為了Mysql的預設存儲引擎,特點是支援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.新特性

可以了解MySQL8.0的一些新特性,例如預設字元集格式改為了UTF8;增加了隐藏索引的功能,隐藏後的索引不會被查詢優化器使用,可以使用這個特性用于性能調試;支援了通用表表達式,使複雜查詢中的嵌入表語句更加清晰;新增了視窗函數的概念,它可以用來實作新的查詢方式。視窗函數與 SUM、COUNT等集合函數類似,但不會将多行查詢結果合并,而是将結果放在多行中。即視窗函數不需要GROUP BY。

▌****8.MySQL調優

索引可以大幅增加資料庫的查詢的性能,在實際業務場景中,或多或少都會使用到。

但是索引是有如下2個代價的:

a.需要額外的磁盤空間來儲存索引

b.對于插入、更新、删除等操作由于更新索引會增加額外的開銷

是以索引比較适合用在讀多寫少的場景。

▌1.MySQL索引類型

如左面的子產品,共分為5類:

  • **唯一索引:**就是索引列中的值必須是唯一的,但是允許出現空值。這種索引一般用來保證資料的唯一性,比如儲存賬戶資訊的表,每個賬戶的id必須保證唯一,如果重複插入相同的賬戶id時會MySQL傳回異常。
  • **主鍵索引:**是一種特殊的唯一索引,但是它不允許出現空值。
  • **普通索引:**與唯一索引不同,它允許索引列中存在相同的值。例如學生的成績表,各個學科的分數是允許重複的,就可以使用普通索引。
  • **聯合索引:**就是由多個列共同組成的索引。一個表中含有多個單列的索引并不是聯合索引,聯合索引是對多個列字段按順序共同組成一個索引。應用聯合索引時需要注意最左原則,就是Where查詢條件中的字段必須與索引字段從左到右進行比對。比如,一個使用者資訊表,用姓名和年齡組成了聯合索引,如果查詢條件是姓名等于張三,那麼滿足最左原則;如果查詢條件是年齡大于20,由于索引中最左的字段是姓名不是年齡,是以不能使用這個索引。
  • **全文索引:**前面提到了,MyISAM引擎中實作了這個索引,在5.6版本後InnoDB引擎也支援了全文索引,并且在5.7.6版本後支援了中文索引。全文索引隻能在CHAR,VARCHAR,TEXT類型字段上使用,底層使用反向索引實作。要注意對于大資料量的表,生成全文索引會非常消耗時間也非常消耗磁盤空間。

▌****2.索引實作

如右面的子產品,索引實作共分4種形式:

  • B+樹實作:b+樹比較适合用作’>‘或’<'這樣的範圍查詢,是MySQL中最常使用的一種索引實作。
  • **R-tree:**是一種用于處理多元資料的資料結構,可以對地理資料進行空間索引。不過實際業務場景中使用的比較少。
  • **Hash:**是使用散清單來對資料進行索引,Hash方式不像Btree那樣需要多次查詢才能定位到記錄,是以Hash索引的效率高于B-tree,但是不支援範圍查找和排序等功能.實際使用的也比較少。
  • **FullText:**就是我們前面提到的全文索引,是一種記錄關鍵字與對應文檔關系的反向索引。

一般MySQL調優有圖中的4個緯度:

  • 針對資料庫設計、表結構設計以及索引設定緯度進行的優化;
  • 對業務中使用的SQL語句進行優化,例如調整Where查詢條件;
  • 對mysql服務的配置進行優化,例如對連結數的管理,對索引緩存、查詢緩存、排序緩存等各種緩存大小進行優化;
  • 對硬體裝置和作業系統設定進行優化,例如調整作業系統參數、禁用Swap、增加記憶體、更新固态硬碟等等。

這四個緯度從優化的成本角度來講,從左到右優化成本逐漸升高;從優化效果角度來看,從右到左優化的效果更高。

對于研發人員來說,前兩個緯度與業務息息相關,是以需要重點掌握,後兩個緯度更适合DBA進行深入學習,簡單了解就好。

▌****1.表結構和索引的優化

第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内部進行特殊處理。

▌****2.SQL語句進行優化的原則

**第1個原則:**要找的最需要優化的SQL語句。要麼是使用最頻繁的語句,要麼是優化後提高最明顯的語句,可以通過查詢MySQL的慢查詢日志來發現需要進行優化的SQL語句;

第2個原則:要學會利用MySQL提供的分析工具。例如使用Explain來分析語句的執行計劃,看看是否使用了索引,使用了哪個索引,掃描了多少記錄,是否使用檔案排序等等。或者利用Profile指令來分析某個語句執行過程中各個分步的耗時;

第3個原則:要注意使用查詢語句是要避免使用Select *,而是應該指定具體需要擷取的字段。原因一是可以避免查詢出不需要使用的字段,二是可以避免查詢列字段的元資訊;

第4個原則:是盡量使用Prepared Statements,一個是性能更好,另一個是可以防止SQL注入;

第5個原則:是盡量使用索引掃描來進行排序,也就是盡量在有索引的字段上進行排序操作。