摘要:要確保沒(méi)有低估需要存儲(chǔ)的值的范圍,更小是相對(duì)與數(shù)據(jù)類型的最大值范圍來(lái)講的。如果無(wú)法確定哪個(gè)數(shù)據(jù)類型是最好的,就選擇你認(rèn)為不會(huì)超過(guò)范圍的最小類型。整數(shù)類型有兩個(gè)類型的數(shù)字整數(shù)和實(shí)數(shù)。列默認(rèn)為,這與其他的數(shù)據(jù)類型不一樣。
簡(jiǎn)述
良好的邏輯設(shè)計(jì)和物理設(shè)計(jì)是高性能系統(tǒng)的基石,比如反范式設(shè)計(jì)可以加快某些類型的查詢同時(shí)也會(huì)影響另外一些類型的查詢效率,所以我們必須重視Mysql對(duì)于數(shù)據(jù)庫(kù)的設(shè)計(jì)(本文主要講述表字段類型對(duì)于數(shù)據(jù)庫(kù)性能的影響)。
由于Mysql獨(dú)有的特性和實(shí)現(xiàn)細(xì)節(jié)對(duì)性能的影響是很明顯的,因?yàn)樽龊肕ysql數(shù)據(jù)庫(kù)的設(shè)計(jì)很關(guān)鍵。對(duì)于數(shù)據(jù)庫(kù)設(shè)計(jì),我們不得不提表字段的類型選擇,由于Mysql支持的數(shù)據(jù)類型非常多,因此如何選擇正確的數(shù)據(jù)類型對(duì)于獲得高性能至關(guān)重要。不管要存儲(chǔ)的數(shù)據(jù)是什么類型,我們都需要根據(jù)一些數(shù)據(jù)庫(kù)設(shè)計(jì)原則來(lái)考慮。
選擇數(shù)據(jù)類型的思考更小的通常是更好的(一般情況下,應(yīng)該盡可能使用正確存儲(chǔ)數(shù)據(jù)的最小數(shù)據(jù)類型。)
為什么呢?
(1) 因?yàn)楦〉臄?shù)據(jù)類型通常更快,因?yàn)樗鼈冋加酶俚拇疟P、內(nèi)存和CPU緩存,并且處理時(shí)需要的CPU周期也更短。 (2) 要確保沒(méi)有低估需要存儲(chǔ)的值的范圍,更小是相對(duì)與數(shù)據(jù)類型的最大值范圍來(lái)講的。 (3) 如果無(wú)法確定哪個(gè)數(shù)據(jù)類型是最好的,就選擇你認(rèn)為不會(huì)超過(guò)范圍的最小類型。
簡(jiǎn)單就好(簡(jiǎn)單數(shù)據(jù)類型的操作通常需要更短的CPU周期。)
為什么呢?下面有幾個(gè)例子說(shuō)明一下原因。
(1) 整型比字符串操作代價(jià)更低,因?yàn)樽址托?duì)規(guī)則(排序規(guī)則)是的字符比較比整型比較更復(fù)雜。 (2) 存儲(chǔ)日期和時(shí)間應(yīng)該使用Mysql內(nèi)建的類型(date,time,datatime)。 (3) IP地址的存儲(chǔ)應(yīng)該用整型(int)。
盡量避免 NULL (空值)
為什么呢?
(1) 很多表都包含可為NULL的列,就算程序并不需要保存NULL也是如此,這是因?yàn)榱械哪J(rèn)屬性就是可為NULL。通常情況下最好指定列NOT NULL,除非真的需要存儲(chǔ)NULL。 (2) 如果查詢中包含可為NULL的列,對(duì)于Mysql來(lái)說(shuō)是很難優(yōu)化的,因?yàn)镹ULL的列使得索引,索引統(tǒng)計(jì)和值比較都更復(fù)雜??蔀镹ULL的列會(huì)使用更多的存儲(chǔ)空間,在Mysql里也需要特殊處理。當(dāng)可為NULL的列被索引時(shí),每個(gè)索引記錄需要一個(gè)額外的字節(jié),在MyISAM里甚至還可能導(dǎo)致固定大小的索引變成可變大小的索引。 (3) 通常把可為NULL的列改為NOTNULL帶來(lái)性能提升比較小,如果計(jì)劃在列上建索引的話,就應(yīng)該盡量避免設(shè)計(jì)成可為NULL的列。(也有一個(gè)例外,那就是在InnoDB中,會(huì)使用多帶帶的位(bit)來(lái)存儲(chǔ)NULL值,所以對(duì)稀疏數(shù)據(jù)有很好的空間效率。)
總結(jié)
在為列選擇數(shù)據(jù)類型時(shí),第一步需要確定合適的大類型(數(shù)字、字符串、時(shí)間等等),這通常是很簡(jiǎn)單的,那么下一步就是選擇具體的類型了。
很多Mysql的數(shù)據(jù)類型可以存儲(chǔ)相同類型的數(shù)據(jù),只是存儲(chǔ)的長(zhǎng)度和范圍不一樣、允許的精度不同,或者需要的物理空間(磁盤和內(nèi)存空間)不同。相同大類型的不同子類型數(shù)據(jù)有時(shí)候也有一些特殊的行為和屬性。
比如:DATATIME 和 TIMESAMP列都可以存儲(chǔ)相同類型的數(shù)據(jù)(時(shí)間和日期)并且精確到秒,然而TIMESTAMP只使用DATATIME一半的存儲(chǔ)空間,并且會(huì)根據(jù)時(shí)區(qū)變化,具有特殊的自動(dòng)更新能力。另外TIMESTAMP允許的時(shí)間范圍要小得多,有時(shí)候它的特殊能力會(huì)成為障礙,這都是我們開發(fā)者需要考慮的。
有兩個(gè)類型的數(shù)字:整數(shù)(whole number)和實(shí)數(shù)(real number)。
如果存儲(chǔ)整數(shù),可以使用這幾種整數(shù)類型:TINNYINT(8)、SMALLINT(16)、MEDIUMINT(24)、INT(32)、BIGINT(64)。
整數(shù)類型有可選的的UNSIGNED屬性,表示不允許為負(fù)值,這大致可以是正數(shù)的上限提高一倍。
比如:TINYINT UNSIGNED可以存儲(chǔ)的范圍是0~255,而TINYINT的存儲(chǔ)范圍是-127~128.
有符號(hào)和無(wú)符號(hào)類型使用相同的存儲(chǔ)空間,并具有相同的功能.
因此可以根據(jù)實(shí)際情況選擇合適的類型。
你的選擇決定Mysql是怎么在內(nèi)存和磁盤中保存數(shù)據(jù)的。
整數(shù)一般選擇64位的BIGINT整數(shù),即使在32位環(huán)境下也是如此。(但是一些聚合函數(shù)是例外,它們是使用DECIMAL或DOUBLE進(jìn)行計(jì)算的)
Mysql可以為整數(shù)類型指定寬度。
比如:INT(11),對(duì)大多數(shù)應(yīng)用這是沒(méi)有意義的:它不會(huì)限制值的合法范圍,只是規(guī)定了Mysql的一些交互工具(例如Mysql命令行客戶端)用來(lái)顯示字符的個(gè)數(shù)。對(duì)于存儲(chǔ)和計(jì)算來(lái)講,INT(1)和INT(20)是相同的。
一些第三方存儲(chǔ)引擎(比如Infobright)有時(shí)也有自定義的存儲(chǔ)格式和壓縮方案,并不一定使用常見的Mysql內(nèi)置引擎的方式。實(shí)數(shù)類型
實(shí)數(shù)是帶有小數(shù)部分的數(shù)字。
它們不只是未來(lái)存儲(chǔ)小數(shù)部分,也可以使用DECIMAL存儲(chǔ)比BIGINT還要大的整數(shù)。Mysql既支持精確類型,也支持不精確類型。
DECIMAL類型用于存儲(chǔ)精確的小數(shù)。
在Mysql5.0或者更高版本支持精確運(yùn)算,而在Mysql4.1以及更早版本中使用浮點(diǎn)運(yùn)算會(huì)出現(xiàn)異常(主要是精度的損失導(dǎo)致的)。
FLOAT和DECIMAL類型都可以指定進(jìn)度。
對(duì)于DECIMAL列可以指定小數(shù)點(diǎn)前后所允許的最大位數(shù),這會(huì)影響列的空間消耗。有很多方法可以指定FLOAT(浮點(diǎn))列所需要的精度,這會(huì)使得Mysql悄悄選擇了不同的數(shù)據(jù)類型,或者在存儲(chǔ)時(shí)對(duì)值進(jìn)行取舍,但是這些精度往往都是非標(biāo)準(zhǔn)的,所以一般建議只指定數(shù)據(jù)類型不指定精度。
由于需要額外的空間和計(jì)算開銷,所以應(yīng)該盡量只在對(duì)小數(shù)進(jìn)行精確計(jì)算時(shí)才使用DECIMAL。
比如存儲(chǔ)財(cái)務(wù)數(shù)據(jù),但是如果數(shù)據(jù)量比較大的時(shí)候,可以考慮使用BIGINT代替DECIMAL,將需要存儲(chǔ)的貨幣單位根據(jù)小數(shù)的位數(shù)乘以相應(yīng)的倍數(shù)即可。
FLOAT和DOUBLE類型支持使用標(biāo)準(zhǔn)的浮點(diǎn)運(yùn)算進(jìn)行近似計(jì)算。
字符串類型Mysql支持多種字符串類型,每種類型還有很多變種。其中VARCHAR和CHAR是兩種最主要的字符串類型。
注意:Mysql存儲(chǔ)引擎存儲(chǔ)CHAR或者VARCHAR值的方式在內(nèi)存中和在磁盤上可能不一樣,所以Mysql服務(wù)器從存儲(chǔ)引擎讀取的值可能需要轉(zhuǎn)換為另外一種存儲(chǔ)格式。
VARCHAR類型用于存儲(chǔ)可變長(zhǎng)字符串,是最常見的字符串?dāng)?shù)據(jù)類型。
VARCHAR比定長(zhǎng)類型更節(jié)省空間,因?yàn)樗鼉H使用必要的空間(越短的字符串使用越少的空間)。
VARCHAR需要使用1或2個(gè)額外字節(jié)記錄字符串的長(zhǎng)度。
VARCHAR節(jié)省了存儲(chǔ)空間,所以對(duì)性能是有幫助的。
下面是一些VARCHAR適合使用的場(chǎng)景:
(1)字符串列的最大長(zhǎng)度比平均長(zhǎng)度大很多。
(2)列的更新很少,所以碎片不是問(wèn)題。
(3)使用了像UTF-8這樣復(fù)雜的字符集,每個(gè)字符都使用不同的字節(jié)數(shù)進(jìn)行存儲(chǔ)。
CHAR類型是定長(zhǎng)的。(Mysql總是根據(jù)定義的字符串長(zhǎng)度分配足夠的空間)
CHAR適合存儲(chǔ)很短的字符串,或者所有值都接近同一個(gè)長(zhǎng)度。
和VARCHAR和CHAR類似的類型還有BINARY和VARBINARY,它們存儲(chǔ)的都是二進(jìn)制字符串。
注意:使用VARCAHR(5)和VARCHAR(200)存儲(chǔ)“hello”的空間開銷都是一樣的,那么使用更短的列有什么優(yōu)勢(shì)呢?(事實(shí)證明有很大的優(yōu)勢(shì))
更長(zhǎng)的列會(huì)消耗更多的內(nèi)存,因?yàn)镸ysql通常會(huì)分配固定大小的內(nèi)存塊來(lái)保存內(nèi)部值。尤其是使用內(nèi)存臨時(shí)表進(jìn)行排序或者操作時(shí)會(huì)特別糟糕。在利用磁盤臨時(shí)表進(jìn)行排序時(shí)也同樣糟糕。
注意:歸根到底,最好的策略是只分配真正需要的空間。
BLOB和TEXT類型BLOB和TEXT都是為存儲(chǔ)很大的數(shù)據(jù)而設(shè)計(jì)的字符串?dāng)?shù)據(jù)類型,分別使用二進(jìn)制和字符方式存儲(chǔ)。
實(shí)際上它們分別屬于兩組不同的數(shù)據(jù)類型家族:
字符串類型有TINYTEXT、SMALLTEXT、TEXT、MEDIUMTEXT、LONGTEXT;
二進(jìn)制類型有TINYBLOB、SMALLBLOB、BLOB、MEDIUMBLOB、LONGBLOB;
ENUM類型可以使用枚舉(ENUM)代替字符串類型。很多時(shí)候建議使用枚舉列代替常用的字符串類型。
(1)枚舉列可以把一些不重復(fù)的字符串存儲(chǔ)成一個(gè)預(yù)定義的集合。
(2)Mysql在存儲(chǔ)枚舉時(shí)非常緊湊,會(huì)根據(jù)列表值的數(shù)量壓縮到一到兩個(gè)字節(jié)中。
(3)Mysql在內(nèi)部會(huì)將每個(gè)值在列表中的位置保存為整數(shù),并且在表的.frm文件中保存“數(shù)字-字符串”映射關(guān)系的“查找表”。
注意:有一個(gè)令人吃驚的地方是,枚舉字段是按照內(nèi)部存儲(chǔ)的整數(shù)而不是定義的字符串進(jìn)行排序的。
注意:枚舉最不好的地方是:字符串列表是固定的,添加或者刪除字符串必須使用ALTER TABLE,因此對(duì)于一系列未來(lái)可能會(huì)改變的字符串,使用枚舉并不是一個(gè)好主意,除非接受只能在列表末尾添加元素。
注意:由于Mysql把每個(gè)枚舉值保存為整數(shù),并且必須進(jìn)行查找才能轉(zhuǎn)換為字符串,所以枚舉列有一些開銷。
日期和時(shí)間類型Mysql有很多類型可以保存日期和時(shí)間值,比如YEAR和DATE。
Mysql能存儲(chǔ)的最小時(shí)間粒度為秒(MariaDB支持微秒級(jí)別的事件類型)。但是Mysql也可以使用微秒級(jí)別的粒度進(jìn)行臨時(shí)運(yùn)算。
大部分時(shí)間類型都沒(méi)有替代品,因此沒(méi)有什么是最佳選擇的問(wèn)題。
接下來(lái)唯一的問(wèn)題是保存日期和時(shí)間的時(shí)候需要做什么。
DATETIME
(1)這個(gè)類型能保存大范圍的值,從1001年到9999年,精度為秒。
(2)DATETIME把時(shí)間和日期封裝到格式為YYYYMMDDHHMMSS的整數(shù)中,與時(shí)區(qū)無(wú)關(guān)。
(3)DATETIME使用8個(gè)字節(jié)的存儲(chǔ)空間。
TIMESTAMP
(1)TIMESTAMP類型保存了從1970年1月1日午夜以來(lái)的秒數(shù),它和UNIX時(shí)間戳相同。
(2)TIMESTAMP只使用4個(gè)字節(jié)的存儲(chǔ)空間,因此它的范圍比DATETIME小得多。
(3)TIMESTAMP顯示的值依賴時(shí)區(qū)。
DATETIME和TIMESTAMP的對(duì)比:
(1)默認(rèn)情況下,如果插入時(shí)沒(méi)有指定第一個(gè)TIMESTAMP列的值,Mysql則設(shè)置這個(gè)列的值為當(dāng)前時(shí)間。(這是DATETIME沒(méi)有的特性)
(2)在插入一行記錄時(shí),Mysql默認(rèn)也會(huì)更新第一個(gè)TIMESTAMP列的值。
(3)TIMESTAMP列默認(rèn)為NOT NULL,這與其他的數(shù)據(jù)類型不一樣。
總結(jié)
(1)除了特殊行為之外,通常也應(yīng)該盡可能使用TIMESTAMP,因?yàn)樗菵ATETIME空間效率更高。
(2)一般來(lái)講不建議把UNIX時(shí)間戳保存為整數(shù)值,這不會(huì)帶來(lái)任何收益,用整數(shù)保存時(shí)間戳格式通常不方便處理。
(3)如果需呀存儲(chǔ)比秒更小粒度的日期和時(shí)間值,可以使用BIGINT類型存儲(chǔ)微秒級(jí)別的時(shí)間戳,或者使用DOUBLE存儲(chǔ)秒之后的小數(shù)部分,也可以用MariaDB替代Mysql。
BIT定義一個(gè)包含單個(gè)位的字段,BIT(2)存儲(chǔ)2個(gè)位,最大長(zhǎng)度是64個(gè)位。
注意:一般建議謹(jǐn)慎使用BIT類型,對(duì)于大部分應(yīng)用來(lái)講最好避免使用這種類型。
選擇標(biāo)識(shí)符為identifier(標(biāo)識(shí)列)選擇合適的數(shù)據(jù)類型非常重要。
一般來(lái)講更有可能用標(biāo)識(shí)列與其他值進(jìn)行比較,或者通過(guò)標(biāo)識(shí)列尋找其他列。
當(dāng)選擇標(biāo)識(shí)列的類型時(shí),不僅僅需要考慮存儲(chǔ)類型,還需要考慮Mysql對(duì)這種類型怎么執(zhí)行計(jì)算和比較。
一旦選定了一種類型,要確保在所有關(guān)聯(lián)表中都使用同樣的類型。
在可以滿足值的范圍需求,并且預(yù)留未來(lái)增長(zhǎng)空間的前提下,應(yīng)該選擇最小的數(shù)據(jù)類型。
注意:整數(shù)通常是標(biāo)識(shí)列最好的選擇,因?yàn)樗鼈兒芸於铱梢允褂肁UTO_INCREMENT。
注意:ENUM和SET是最糟糕的選擇了;如果可能也盡可能避免使用字符串作為標(biāo)識(shí)列,因?yàn)樗鼈兒芟目臻g并且通常比數(shù)字類慢。
對(duì)于數(shù)據(jù)庫(kù)設(shè)計(jì),一定要三思而后行,選擇最適合的數(shù)據(jù)列類型還有決定數(shù)據(jù)列的大小都是很關(guān)鍵的一步。
其實(shí)大可不必驚慌,無(wú)論對(duì)于任何類型需求的數(shù)據(jù)表設(shè)計(jì),你只要記住一個(gè)原則,很重要很重要很重要的原則:盡可能使用正確存儲(chǔ)數(shù)據(jù)的最小數(shù)據(jù)類型。
PS:很晚了,總結(jié)先草草了事,日后還會(huì)更新......
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/35750.html
摘要:要確保沒(méi)有低估需要存儲(chǔ)的值的范圍,更小是相對(duì)與數(shù)據(jù)類型的最大值范圍來(lái)講的。如果無(wú)法確定哪個(gè)數(shù)據(jù)類型是最好的,就選擇你認(rèn)為不會(huì)超過(guò)范圍的最小類型。整數(shù)類型有兩個(gè)類型的數(shù)字整數(shù)和實(shí)數(shù)。列默認(rèn)為,這與其他的數(shù)據(jù)類型不一樣。 簡(jiǎn)述 良好的邏輯設(shè)計(jì)和物理設(shè)計(jì)是高性能系統(tǒng)的基石,比如反范式設(shè)計(jì)可以加快某些類型的查詢同時(shí)也會(huì)影響另外一些類型的查詢效率,所以我們必須重視Mysql對(duì)于數(shù)據(jù)庫(kù)的設(shè)計(jì)(本...
showImg(https://segmentfault.com/img/remote/1460000007103938?w=391&h=247); 文章最初發(fā)表于我的個(gè)人博客非典型性程序猿 對(duì)于剛接觸JAVA或者其他面向?qū)ο缶幊陶Z(yǔ)言的朋友們來(lái)說(shuō),可能一開始都很難理解面向?qū)ο蟮母拍钜约邦惡蛯?duì)象的關(guān)系。筆者曾經(jīng)帶過(guò)一個(gè)短期培訓(xùn)班教授java入門基礎(chǔ),在最后結(jié)束課程的時(shí)候,還有很多同學(xué)不太理解面向?qū)ο?..
摘要:使用簡(jiǎn)記后端掘金全稱為即消息隊(duì)列。優(yōu)測(cè)優(yōu)社區(qū)干貨精選老司機(jī)亂談編輯器之神掘金前言是一種信仰,我自從年有了這個(gè)信仰,已經(jīng)個(gè)年頭了。 PHP 程序員進(jìn)階學(xué)習(xí)書籍參考指南 - 后端 - 掘金PHP程序員進(jìn)階學(xué)習(xí)書籍參考指南 @heiyeluren lastmodify: 2016/2/18 ... 當(dāng)我們?cè)谡務(wù)撉岸思用軙r(shí),我們?cè)谡勑┦裁?- 前端 - 掘金潘建旭,豈安科技(www.bigse...
閱讀 1644·2023-04-25 18:19
閱讀 2090·2021-10-26 09:48
閱讀 1094·2021-10-09 09:44
閱讀 1745·2021-09-09 11:35
閱讀 3037·2019-08-30 15:54
閱讀 2033·2019-08-30 11:26
閱讀 2297·2019-08-29 17:06
閱讀 893·2019-08-29 16:38