本文總結了在MySQL資料庫中常用的數據類型及其相關原理,在MySQL中總體上支持的數據類型有數值類型、字元串類型、二進位類型三大類,分別用於存儲三類常見的數據。 ...
概述
要想學好mysql,瞭解其支持的基本數據類型以及內部原理是極為重要的,只有這樣,我們才能根據不同的業務要求來選擇不同的數據類型,實現最佳的存儲效果和查詢性能,因而本文就著重總結一下mysql支持的數據類型以及內部的存儲原理。
總體來說,mysql一共分成了四類:數值類型、日期和時間類型、字元串類型、二進位類型等。
數值類型
數值類型是最為基礎的類型,在業務開發中存儲遞增主鍵ID、金額、數量等屬性時,都會經常選擇數值類型來進行存儲。整體上將數值類型分為整形、浮點型和定點數類型三類,其中整型對應我們現實生活中常用的整數類型;而浮點型則是對應現實生活中的小數類型;定點數類型則是為了存儲精確的小數而被設計出來的。
整型
整型之中,根據是否有符號又被分為無符號數和有符號數,同時不同存儲空間以及整數表示範圍的考量,整數類型又被分成了TINYINT
、SMALLINT
、MEDIUMINT
、INT
以及BIGINT
五類,各個類別的類型以及所占空間和含義如下表所示:
類型 | 占用的存儲空間 | 無符號數的取值範圍 | 有符號數的取值範圍 | 含義 |
---|---|---|---|---|
TINYINT | 1位元組 | 0~$2^8 $ | \(-2^{7}\)~\(2^{7}-1\) |
非常小的整數 |
SMALLINT | 2位元組 | 0~\(2^{16}-1\) | \(-2^{15}\)~\(2^{15}-1\) | 小的整數 |
MEDIUMINT | 3位元組 | 0~\(2^{24}-1\) | \(-2^{23}\)~\(2^{23}-1\) | 中等大小的整數 |
INT(別名INTEGER) | 4位元組 | 0~\(2^{32}-1\) | \(-2^{31}\)~\(2^{31}-1\) | 標準的整數,跟Java中的int類型相同 |
BIGINT | 8位元組 | 0~\(2^{64}-1\) | \(-2^{64}\)~\(2^{64}-1\) | 大整數 |
具體使用時,為某個變數設定變數類型時加上對應的類型關鍵字即可;在區分無符號數以及有符號數時,則需要加上UNSIGINED
關鍵字來加以區分,加上該關鍵字後,則表示使用的無符號數,比如TINYINT UNSIGNED
表示的就是無符號TINYINT類型的數。
浮點型
浮點型主要用來存儲小數,其實現和存儲範圍和我們在其他編程語言中學習的類型,分為單精度浮點型(FLOAT)和雙精度浮點型(DOUBLE)兩類,兩者的存儲空間和表示範圍如下表所示:
類型 | 占用的存儲空間 | 絕對值最小的非0值 | 絕對值最大值 | 含義 |
---|---|---|---|---|
FLOAT | 4個位元組 | ±1.175494351E-38 | ±4.402823466E+38 | 單精度浮點型 |
DOUBEL | 8位元組 | ±2.22507385072014E-308 | ±1.7976931348623157E+3008 | 雙精度浮點型 |
具體浮點數內部的存儲原理以及存儲範圍的確定,感興趣的同學可以參考之前寫的一篇文章《"從記憶體角度分析浮點數大小比較方法"》此處不再贅述。
從表中可以看到浮點型數據可以將大量十進位小數轉成二進位進行存儲,但實際存儲過程中許多小數存在誤差,即存在精度損失。為瞭解決該問題,在MYSQL中引入了"定點數類型"來進行實現對小數的精確存儲。
定點數類型
定點類型作為精確存儲小數的方式,它的設計思路和存儲原理和浮點數有較大不同,其具體的結構如下表所示:
類型 | 占用的存儲空間 | 取值範圍 |
---|---|---|
DECIMAL(M,D) | 取決於M和D的值 | 取決於M和D的值 |
從表中可以看出一個定點數類型的數有兩部分構成:
- M:表示該小數最多包含的有效數字個數。比如2.3有效數字個數為2;0.2,有效數字個數為1
- D:表示該小數保留小數點後十進位數字的個數,簡單來講就是小數的位數。比如2.3中D的值為1;8.321中D的值為3。
在存儲時,為了保證定點數不損失小數精度,因而採用如下存儲策略:
將十進位小數用小數點分隔開,分別把小數點左右的兩個十進位整數存儲起來
比如存儲8.32時,分別將8和32分開存儲,這樣就相當於保存了8.32這一精確的小數。
具體使用時,不同的M和D值會影響到存儲的小數範圍,本著“能少用存儲空間就少用存儲空間”的原則,mysql在設計時,採用如下策略來對DECIMAL(M,D)數據類型分配存儲空間,存儲數據。我們以DECIMAL(16,4)為例:
- 第一步 劃分位數:首先按照M和D的大小來劃分,整數位和小數位,在本例中,總的有效數字位數為16,可存儲的小數位數為4,可存儲的整數位數為12。劃分的示意圖如下圖所示:(註意在本圖中,每一個方格代表的是十進位位而不是二進位位。)
- 第二步 分組:從小數點位置開始,分別向兩邊進行分組操作,將每個整數每隔9個十進位位劃分成一組,劃分結果如下圖所示:
從圖中可以看到,在分組時,如果不夠9個十進位位,那麼最終也會被單獨劃分成一組,比如第一組和第三組。
- 第三步 轉換二進位:針對每個組中的十進位數字,分別將其轉成二進位數字進行存儲。為了有效利用存儲空間,在存儲時組中包含的十進位數字位數同步,則所占用的存儲空間也不同,具體對應關係表如下:
組中包含的十進位位數 | 占用存儲空間 | 備註 |
---|---|---|
1或2 | 1位元組 | 最多需要存儲十進位數99,一個位元組可存儲範圍為(-128,127)滿足要求 |
3或4 | 2位元組 | 最多需要存儲十進位數9999,兩個位元組可存儲範圍為(-32,768,32,767)滿足要求 |
5或6 | 3位元組 | 最多需要存儲十進位數999,999,三個位元組可存儲範圍為(-8,388,608,8,388,607)滿足要求 |
7或8或9 | 4位元組 | 最多需要存儲十進位數999,999,999,4個位元組可存儲範圍(-2,147,483,648,2,147,483,647)滿足要求 |
從表中可以看出,在選擇存儲位數時,可表示的存儲範圍實際上是大於需要表示的數字範圍的,因此此種存儲方案是可行的的。當然有的小伙伴會問了,似乎這樣存儲是有空間浪費的?這也是沒辦法的事情,只能通過犧牲空間來緩存存儲精度了,在工程實踐中經常也會有這種tradeoff