CTO之瞳-數據庫-MySql

​數據,是所有軟件業務系統的根本。業務生長於數據之上,最終又歸於數據。數據的設計、處理與保存是否合理,決定了系統的穩固性以及可拓展性。因此,我們先從數據庫說起。

1.DBMS

數據庫,存儲數據的倉庫。

假如沒有數據庫,程序還能寫的出來嗎?當然可以,早期沒有專業數據庫的時候,程序員通常把數據放在文件中存進存儲介質。但程序員需要自己設計數據的增刪改查算法與代碼,同時需要自己保證數據的安全性與可靠性。而這一切,耗時費力。

數據庫的誕生,把以上關於數據操作的活兒都做了,程序員只要集中精力設計數據庫表的結構與字段就可以了。關於數據操作的效率、安全等方面,全部交給專業的數據庫設計人員去實現。

因此,通常所說的xxx數據庫並不準確,應該稱其為xxx數據庫管理軟件(Database Management Software,DBMS)。數據庫,其實是一整套數據管理的軟件集合。

2.DBMS的分類

通常度娘出來的DBMS分類為兩類:關係型數據庫、非關係型數據庫(NoSql),個人認為這樣的分類已經失去意義。通常所說的非關係型數據庫(NoSql)裡,包含了文檔數據庫MongoDB,包含了鍵值對數據庫Redis、Memcached,包含了分佈式數據庫HBase,還包含了時序數據庫InfluxDB,這幾種類型個人看來都是可以和關係型數據庫並列的。

實際上DB-Engines排名中的分類也是如此區分的,各位可以參考。

https://db-engines.com/en/ranking

每一個分類的定義與解釋,由於不是科普類文章,這裡就不搬磚了。上面的網頁點進去後,有專業的名詞解釋。

3.使用哪些DBMS?

對於一箇中小型業務系統,一般使用MySql + MongoDB可以滿足大部分的業務需求。

近來年由於IoT的興起,如果業務與物聯網有關的話,再加一個時序數據庫InfluxDB。例如,一些工業管網體系有成千上萬個監測點,每個監測點的硬件終端按秒級上報監控狀態,用以監控管網的運作情況。在這種場景下,使用傳統數據庫也許可以完成數據的記錄,但是等到要按時間維度做多重數據分析的時候,傳統數據庫便無法勝任了。

隨著業務的發展,如果業務量大到數據庫成為瓶頸時,可以考慮使用Memcached之類的緩存技術提升數據讀寫的性能。

所以個人觀點,MySql + MongoDB + InfluxDB +Memcached組合,可以支撐大多數中小型業務系統的設計。

4.MySql

接下來,正式開始MySql相關的內容。

  1. 由於不是搬磚文,所以關於MySql的安裝使用等基礎知識,此文並不會涉及,推薦各位直接閱讀菜鳥教程https://www.runoob.com/mysql/mysql-tutorial.html
  2. 以下所有分析基於開發環境:MySql 5.7.22(Windwos版),IDEA 2019,Windows10, i7-9700F, 8G內存, 東芝固態硬盤
  3. 相關代碼訪問路徑:https://gitlab.com/ctoeyes/mysql

4.1 MySql – DB Engine之InnoDB與MyISAM

先說一說DB Engine(數據庫引擎)的概念,看下圖。

CTO之瞳-數據庫-MySql


數據庫引擎是數據庫管理軟件裡直接操控數據庫實體硬件存儲介質的一環,MySql有多種DB Engine可供選擇,常用的有MyISAM、InnoDB。創建一張表時,可以指定DB Engine的類型,默認是InnoDB。

為什麼要有多種DB Engine類型呢?因為每一種的特點不一樣,針對不同業務用途,可以選擇不同的類型。

以InnoDB與MyISAM為例,有三個較大的區別

- InnoDB支持事務(ACID),MyISAM不支持。

- InnoDB行級鎖,MyISAM表級鎖。

- 兩者讀寫性能與存儲空間有差異,請看下面的實驗結果。

首先,設計兩張一樣的表,一張使用InnoDB引擎,另一張使用MyISAM引擎。

建表sql如下:

CREATE TABLE `innodb` ( `A` varchar(32) DEFAULT NULL, `B` int(11) NOT NULL, `C` varchar(32) DEFAULT NULL, `D` int(11) DEFAULT NULL, PRIMARY KEY (`B`)) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE TABLE `myisam` ( `A` varchar(32) DEFAULT NULL, `B` int(11) NOT NULL, `C` varchar(32) DEFAULT NULL, `D` int(11) DEFAULT NULL, PRIMARY KEY (`B`)) ENGINE=MyISAM DEFAULT CHARSET=utf8

實驗一、單線程連續插入5萬條數據。

InnoDB耗時約35秒,MyISAM耗時約2秒。

CTO之瞳-數據庫-MySql

實驗二、單線程連續查詢一萬次,每次以D列作為查詢條件。

InnoDB耗時約75秒,MyISAM耗時約34秒。

CTO之瞳-數據庫-MySql

由此可見,單線程情況下,MyISAM引擎查詢與插入的性能均大大優於InnoDB。

擴展題:多線程,同時插入與查詢的情況下,哪一種引擎的表現會更好?

實驗三、兩張表有5萬條相同的數據,它們的空間使用情況如下。

CTO之瞳-數據庫-MySql

MyISAM的數據以及索引總共佔用1.5M左右空間,而InnoDB佔用了接近10M。

綜上,使用MySql數據庫,如果不要求事務性,使用MyISAM引擎性能和空間上更佔優勢。如果業務讀多寫少,使用MyISAM也更合適。

例如,中小型公司的內部OA、售後等併發量小,對於延遲不敏感的系統均可以使用MyISAM。

4.2 MySql – 索引與B+樹

上一節在查詢時,使用了非索引列D作為查詢條件。在兩張表裡,列B與列D的數據是完全一樣的,列B被定義為主鍵(非空索引)。如果使用列B作為查詢條件,結果是這樣的。

CTO之瞳-數據庫-MySql

同樣1w次查詢,InnoDB耗時約700ms,MyISAM耗時約500ms。對比之前的75秒與34秒,是不是有種起飛的感覺?這就是索引的作用。

對於新手來說,如果數據查詢性能有問題,先看一看代碼裡的查詢條件是否使用了索引。

那是不是把所有能設為索引的列都設為索引呢?不是。第一個原因:索引都要佔用一定的存儲空間。第二個原因:大量的索引會導致數據表的更新、插入、刪除變慢(需要更新索引)。

索引是什麼呢?索引是一種數據結構,MySql裡使用的是稱之為B+樹的數據結構。

假設我們有9條數據,每條數據有4列值,分別為Name、ID、Age、Seat No,其中ID為主鍵,Seat No又設為了索引。


CTO之瞳-數據庫-MySql


那麼在MySql裡(InnoDB引擎),這些數據是長成下圖這樣的,這裡就不做具體的解釋了,相信程序猿都看得懂。


CTO之瞳-數據庫-MySql


雖然在日常開發中並不需要知道MySql的底層數據結構長什麼樣,但理解每種數據庫的數據結構,有助於選擇合適的數據庫,併合理的設計數據表、主鍵、索引等。

4.3 MySql – 分庫分表

隨著表數據以及容量的增加,增刪改查的效率都會隨之下降。那麼當表數據量大到什麼程度時,效率會低到無法容忍了呢?網上流傳的阿里數據庫MySql設計規範裡(未證實)有這麼一句“單表數據量超過500w或數據容量超過10G考慮分表”。

上面這個分表的參考標準,相信是無數開發、測試與DBA經驗的總結,在此並無意質疑。但這個標準一定準確嗎?個人並不認為。這個標準裡並沒有承載數據庫的硬件參數作為參考值,同樣的庫表部署在不同的硬件上,性能是會有很大差異的。下圖來源於MySql的官方測試結果,可以看到隨著CPU內核數的增加,MySql 5.6的性能是逐漸提升的。

CTO之瞳-數據庫-MySql


所以,經驗值是供參考的,應用時得考慮實際情況,不能照本宣科。

不管怎樣,隨著業務的發展,總有一天需要通過某些方法去提升數據庫的性能。

常見的方法有:

分庫:最簡單有效的方法。一個業務系統的數據放在一個獨立的物理數據庫裡,比如賬戶信息、交易信息、物流信息都單獨存放在一臺實體數據庫中,性能一定是槓槓的。當然,成本也一定是最高的。

垂直分表:假設一張表有4個字段,如果業務上經常通過ID查詢用戶名,而年齡和座位號並不常用,那麼可以拆為兩張表,如下所示。

CTO之瞳-數據庫-MySql


這樣拆分,如果業務上要查詢坐在座位20上的人叫什麼名,或者有多少個7歲的Tommy時,本來單表查詢可以完成的工作就要採用JOIN語句了。

水平分表:按照ID的奇偶數分為兩張不同的表,減少單表的容量。

CTO之瞳-數據庫-MySql


這樣拆分,對於很多業務查詢需求,需要採用UNION語句對多張表進行處理。

擴展:曾經被問過一個問題,假設有一張交易訂單表,按照時間維度進行水平拆分,由於用戶通常會訪問最近的交易信息,因此大部分的查詢還是命中在同一張表裡,如何處理?有些低頻用戶,隔幾個月才交易一次,如果查詢此類用戶的最近10單交易,需要去多張表甚至多個庫訪問,查詢比較耗時,如何處理?

分庫分表,提升了數據增刪改查的性能。但由於數據的分離,一段業務邏輯需要使用的數據原本從一張表裡就可以拿到,現在可能要去不同庫的好幾張表裡獲取,增加了代碼編寫的複雜度。針對這種情況,一類數據庫中間件應運而生,代表性的有MyCat。

MyCat可以看做是一個內部服務,業務系統對於數據的操作保持不變,sql語句發到MyCat,由MayCat解析後去不同的數據庫和數據表操作,然後把操作結果返回給業務系統。

不過,在這裡想說的是,如果業務數據分庫分表複雜到需要使用MyCat之類的中間件時,MySql可能就不是一個好的數據庫選擇去應對業務的發展了。更正確的方向,應該考慮使用一種新的數據庫去處理增長的業務數據需求。

4.4 MySql – MySql Router

在分庫分表、使用MyCat之前,建議先考慮MySql DBMS中一個原生的輕量級中間件:MySql Router。

使用MySql Router組一個簡單的2-3臺主從機策略,可以方便快捷的達到以下幾個目的

- 提升性能

- 數據備份

- 故障熱切換

- 負載均衡

- 讀寫分離

CTO之瞳-數據庫-MySql

好了,關於MySql就寫到這裡,下一篇《數據庫-MongoDB》。

寫在最後的一些話:以上關於MySql的這些內容並不複雜,基本上是一個初中級的程序員應該掌握的,而在DBA眼裡就更ez了。寫這些內容,是想說明幾個道理,如果想做一個好的程序員並且成長為架構師甚至CTO,需要

- 具備獨立思考的能力,而不光是學(chao)習(xi)的能力。技術種類有很多,各類觀點也很多,怎樣結合實際業務需求,做出準確的判斷需要我們獨立思考(當然交流也是必須的)。如果我們只是聽前輩的言傳身教,學到的永遠只是皮毛。就好比嬰兒一直吃母親嚼碎的食物,沒法具備自己咀嚼的能力。

- 紙上得來終覺淺,絕知此事要躬行。聽別人說的,看別人寫的,不如自己做幾個實驗,畫幾張圖理解的更深刻。

- 要想脫離CRUD,需要系統的學習,而不是各大論壇網站東拼西湊。


分享到:


相關文章: