深入理解MySQL數(shù)據(jù)類(lèi)型的選擇優(yōu)化
前言
介紹了MySQL的常用數(shù)據(jù)類(lèi)型的基本特性,以及數(shù)據(jù)類(lèi)型的選擇優(yōu)化。
MySQL數(shù)據(jù)類(lèi)型是定義列中可以存儲(chǔ)什么數(shù)據(jù)以及該數(shù)據(jù)實(shí)際怎樣存儲(chǔ)的基本規(guī)則,正確的選擇數(shù)據(jù)庫(kù)字段的字段類(lèi)型對(duì)于數(shù)據(jù)庫(kù)性能有很大的影響。
1 整數(shù)類(lèi)型
整數(shù)類(lèi)型有五種:TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,分別使用1、2、3、4、8字節(jié)(8、16、24、32、64位)的存儲(chǔ)空間。
可以存儲(chǔ)的值的范圍從-2^(N-1)到2^(N-1)-1,其中N是存儲(chǔ)空間的位數(shù),比如TINYINT,它的存儲(chǔ)范圍就是-128-127。
所有的整數(shù)類(lèi)型都默認(rèn)是有符號(hào)數(shù),即可正可負(fù)。所有的整數(shù)類(lèi)型都可以設(shè)置unsigned屬性,這表示將該整數(shù)字段無(wú)符號(hào)化,即不允許負(fù)值,這種操作大致可以使正數(shù)的上限提高一倍,例如TINYINT,unsigned可以存儲(chǔ)的范圍是0-255。
有符號(hào)數(shù)和無(wú)符號(hào)數(shù),使用相同的存儲(chǔ)空間,具有相同的性能,因此可以根據(jù)實(shí)際情況選擇。但請(qǐng)注意,MySQL數(shù)據(jù)庫(kù)中unsigned數(shù)的操作結(jié)果都是unsigned的,因此如果執(zhí)行了計(jì)算,并且結(jié)果是負(fù)數(shù),那么最終結(jié)果將難以預(yù)測(cè),慎用unsigned。
和整數(shù)的類(lèi)型無(wú)關(guān)的是,整數(shù)的計(jì)算一般使用有64位的BIGINT整數(shù),即使在32位的環(huán)境中即是如此。
MySQL可以為整數(shù)指定寬度,例如int(1),但這對(duì)大多數(shù)應(yīng)用都是無(wú)意義的:它不會(huì)限制值的合法范圍,只是規(guī)定了MySQL的一些交互工具如MySQL命令客戶(hù)端)顯示字符的個(gè)數(shù),而不是指定的存儲(chǔ)大小。int(1)和int(10)對(duì)存儲(chǔ)和計(jì)算來(lái)說(shuō)是相同的,但這個(gè)規(guī)則只適用于整數(shù)類(lèi)型而不適用于varchar和char類(lèi)型。
2 實(shí)數(shù)類(lèi)型
實(shí)數(shù)就是帶有小數(shù)部分的數(shù)字,然而它們不止是為了存儲(chǔ)小數(shù)部分,也可以使用DECIMAL存儲(chǔ)比BIGINT還大的整數(shù)。實(shí)數(shù)類(lèi)型有三種:FLOAT、DOUBLE、DECIMAL。
實(shí)數(shù)都可以指定精度,例如DECIMAL(18,9),這表示值存儲(chǔ)的有效位數(shù)為18,并且小數(shù)點(diǎn)后可以存儲(chǔ)的位數(shù)為9,因此整數(shù)部分的位數(shù)同樣也是9。MySQL 在存儲(chǔ)值時(shí)執(zhí)行舍入,因此如果將 89.0009 插入FLOAT(6,3) 列,則近似結(jié)果為 89.001。
MySQL既支持精確類(lèi)型,也支持不精確類(lèi)型。FLOAT和DOUBLE類(lèi)型支持使用標(biāo)準(zhǔn)的浮點(diǎn)運(yùn)算進(jìn)行近似計(jì)算,稱(chēng)為浮點(diǎn)數(shù),F(xiàn)LOAT固定占4個(gè)字節(jié),DOUBLE固定占8個(gè)字節(jié),精度更高。和整數(shù)類(lèi)型一樣,浮點(diǎn)只能選擇存儲(chǔ)類(lèi)型,在計(jì)算時(shí),MYSQL5使用DOUBLE作為內(nèi)部浮點(diǎn)計(jì)算的類(lèi)型。
DECIMAL類(lèi)型則用于存儲(chǔ)精確的小數(shù),在MYSQL5.0以及更高的版本中,DECIMAL類(lèi)型支持精確計(jì)算。DECIMAL 的最大允許65個(gè)數(shù)字。DECIMAL列使用二進(jìn)制格式進(jìn)行存儲(chǔ),MYSQL5.0和更高版本中,會(huì)將數(shù)字打包保存到一個(gè)二進(jìn)制字符串中:每個(gè)值的小數(shù)點(diǎn)占據(jù)一個(gè)字節(jié),每個(gè)值的整數(shù)和小數(shù)部分的存儲(chǔ)要求分別確定,每9個(gè)十進(jìn)制的數(shù)字被打包為4個(gè)字節(jié),剩余的需要另外打包:
剩下的數(shù)字 | 所需字節(jié)數(shù) |
---|---|
0 | 0 |
1-2 | 1 |
3-4 | 2 |
5-6 | 3 |
7-9 | 4 |
例如,DECIMAL (18, 9)小數(shù)點(diǎn)兩邊都有9位數(shù),因此兩邊都需要4個(gè)字節(jié),另外小數(shù)點(diǎn)本身占一個(gè)字節(jié),一共需要九個(gè)字節(jié)。
CPU不支持DECIMAL的精確計(jì)算,精確計(jì)算是MySQL服務(wù)器自身實(shí)現(xiàn)的,因此需要額外的的空間和計(jì)算開(kāi)銷(xiāo)。CPU直接支持浮點(diǎn)運(yùn)算,所以浮點(diǎn)運(yùn)算更快,所以盡量只在需要對(duì)小數(shù)進(jìn)行精確計(jì)算時(shí)使用DECIMAL類(lèi)型(如與錢(qián)相關(guān)的數(shù)據(jù))。
在數(shù)據(jù)量比較大的時(shí)候,可考慮使用BIGINT代替DECIMAL,此時(shí)只需根據(jù)小數(shù)位數(shù)乘以相應(yīng)的倍數(shù)即可。比如,如果存儲(chǔ)的財(cái)務(wù)數(shù)據(jù)精確到萬(wàn)分之一時(shí),可以把所有的金額乘以一百萬(wàn),然后將結(jié)果存入BIGINT里,這樣就可以避免浮點(diǎn)存儲(chǔ)計(jì)算不準(zhǔn)確和DECIMAL精度計(jì)算代價(jià)高的問(wèn)題。
3 字符串類(lèi)型
MySQL支持多種字符串類(lèi)型,主要的有:VARCHAR、CHAR、BLOB、TEXT、ENUM等。
3.1 VARCHAR和CHAR類(lèi)型
VARCHAR和CHAR是兩種最主要的數(shù)據(jù)類(lèi)型,但是不同的存儲(chǔ)引擎會(huì)將這兩種數(shù)據(jù)類(lèi)型以不同的樣式存入磁盤(pán)和內(nèi)存中,下面是InnoDB或者M(jìn)yISAM存儲(chǔ)引擎中VARCHAR和CHAR的介紹。
VARCHAR類(lèi)型:
- VARCHAR類(lèi)型用于存儲(chǔ)可變長(zhǎng)度的字符串,是最常見(jiàn)的字符串?dāng)?shù)據(jù)類(lèi)型,它比定長(zhǎng)類(lèi)型的CHAR更節(jié)省空間,因?yàn)樗鼉H使用必要的空間。實(shí)際長(zhǎng)度由最長(zhǎng)的行的大小和使用的字符集確定。
- VARCHAR需要一個(gè)或者兩個(gè)額外的字節(jié)記錄字符串長(zhǎng)度,VARCHAR列的最大長(zhǎng)度小于或等于255個(gè)字節(jié)時(shí)需要一個(gè)字節(jié)來(lái)記錄,大于255時(shí)需要兩個(gè)字節(jié)來(lái)記錄。例如VARCHAR(10)的列需要11個(gè)字節(jié)的存儲(chǔ)空間,VARCHAR(1000)的列則需要1002個(gè)字節(jié)。(字符串長(zhǎng)度不是指的字節(jié)數(shù),而是字符數(shù),因此多字節(jié)字符會(huì)需要更多的空間存儲(chǔ),比如中文)。
- 雖然VARCHAR節(jié)省了存儲(chǔ)空間,但是在UPDATE列時(shí)如果使得行變得比原來(lái)更長(zhǎng),這就可能導(dǎo)致需要額外的工作,如果一個(gè)行占用的空間增長(zhǎng),并且在頁(yè)內(nèi)沒(méi)有更多空間可以存儲(chǔ)時(shí),InnoDB引擎就會(huì)做頁(yè)分裂這個(gè)額外的操作來(lái)使行可以放進(jìn)頁(yè)內(nèi),而MyISAM則會(huì)將行拆成不同的片段存儲(chǔ)。
- 如果字符串列的最大長(zhǎng)度可能比平均長(zhǎng)度大很多,并且列的更新很少,那么建議使用VARCHAR類(lèi)型。
- 在MYSQL 5.0及更高版本,MYSQL在使用VARCHAR存儲(chǔ)和檢索時(shí)會(huì)保留字符串末尾的空格,但在4.1或更老的版本,MYSQL會(huì)trim剔除末尾空格。
- 如果使用InnoDB引擎,那么過(guò)長(zhǎng)的VARCHAR會(huì)被存儲(chǔ)為BLOB。
CHAR類(lèi)型:
- CHAR類(lèi)型是定長(zhǎng)的:MySQL總是根據(jù)定義的字符串長(zhǎng)度分配足夠的空間。
- CHAR值會(huì)根據(jù)需要采用空格進(jìn)行填充以方便比較(插入長(zhǎng)度小于定義長(zhǎng)度時(shí))。
- CHAR適合存儲(chǔ)很短的字符串,或者所有值都接近同一個(gè)長(zhǎng)度。例如,CHAR非常適合存儲(chǔ)密碼的MD5值,因?yàn)檫@是一個(gè)定長(zhǎng)的值。
- 對(duì)于經(jīng)常變更的數(shù)據(jù),CHAR也比VARCHAR更好,因?yàn)?strong>定長(zhǎng)的CHAR類(lèi)型不容易產(chǎn)生碎片。
- 對(duì)于非常短的列,CHAR比VARCHAR在存儲(chǔ)空間上也更有效率,如存儲(chǔ)只有“Y”或"N"的值,如果采用單字節(jié)字符集,使用CHAR(1)占用一個(gè)字節(jié),而VARCHAR (1)占用兩個(gè)字節(jié)(一個(gè)字節(jié)用于存儲(chǔ)長(zhǎng)度);
- 當(dāng)存儲(chǔ)和檢索CHAR值時(shí),MySQL會(huì)刪除所有末尾空格。
如下案例:
CREATE TABLE test(a VARCHAR(4), b CHAR(4)); INSERT INTO test VALUES ('ab ', 'ab '); SELECT CONCAT(a, '+'), CONCAT(b, '+') FROM test;
結(jié)果如下:
另外,數(shù)據(jù)如何存儲(chǔ)取決于存儲(chǔ)引擎,比如Memeory引擎只支持定長(zhǎng)的行,即使有變長(zhǎng)字段,也會(huì)根據(jù)最大長(zhǎng)度分配空間。但是對(duì)于填充和截取空格的行為在不同的存儲(chǔ)引擎都是一樣的,因?yàn)檫@是在MySQL服務(wù)器進(jìn)行處理的。
另外,雖然VARCHAR(5)和VARCHAR(200)存儲(chǔ)"hello"的磁盤(pán)空間開(kāi)銷(xiāo)是一樣的,然是使用更短的列仍然有很大的優(yōu)勢(shì)。因?yàn)楦L(zhǎng)的列會(huì)消耗更多的內(nèi)存,因?yàn)閙ysql通常會(huì)分配固定大小的內(nèi)存塊來(lái)保存內(nèi)部值,尤其是使用內(nèi)存臨時(shí)表來(lái)進(jìn)行排序或操作時(shí)特別糟糕,在利用磁盤(pán)臨時(shí)表進(jìn)行排序時(shí)也同樣糟糕。因此最好的策略是只分配真正需要的空間。
3.1.1 最大長(zhǎng)度
MySQL4.1版本之前,varchar(n),指的是n個(gè)字節(jié),如果存放UTF8類(lèi)型字符時(shí),只能存n/3個(gè)字符(每個(gè)字符占3個(gè)字節(jié))。
MySQL4.1版本開(kāi)始,varchar(n),指的是n個(gè)字符,無(wú)論存放的是數(shù)字、字母還是漢字,都可以存放3個(gè),但是字節(jié)數(shù)不能超過(guò)最大限制。
首先,一張表中所有字段的長(zhǎng)度總和不超過(guò)65535字節(jié)。
CHAR類(lèi)型最大長(zhǎng)度為255個(gè)字符(字符數(shù)量,而非字節(jié)數(shù)量)。
而VARCHAR類(lèi)型的最大長(zhǎng)度則是可變的,需要計(jì)算,VARCHAR的最大長(zhǎng)度還與字符集有關(guān)。如果一張表有VARCHAR和CHAR類(lèi)型的字段分別一個(gè),采用utf8mb4編碼(一個(gè)字符最多占4個(gè)字節(jié)),那么所有字段一共最多65535/4=16383.75=16383個(gè)字符長(zhǎng)度,如果其中CHAR類(lèi)型的字段長(zhǎng)度為5,那么VARCHAR類(lèi)型的最大長(zhǎng)度則是16378。
- 字符類(lèi)型若為latin1,每個(gè)字符最多占1個(gè)字節(jié),最大長(zhǎng)度不能超過(guò)65532。
- 字符類(lèi)型若為gbk,每個(gè)字符最多占2個(gè)字節(jié),最大長(zhǎng)度不能超過(guò)32766。
- 字符類(lèi)型若為utf8,每個(gè)字符最多占3個(gè)字節(jié),最大長(zhǎng)度不能超過(guò)21844。
- 字符類(lèi)型若為utf8mb4,每個(gè)字符最多占4個(gè)字節(jié),最大長(zhǎng)度不能超過(guò)16383。
3.2 Binary和VarBinary類(lèi)型
Binary和VarBinary用于存儲(chǔ)二進(jìn)制字符串,存儲(chǔ)的是字節(jié)碼而非字符。
MySQL在填充Binary時(shí)用的是\0(零字節(jié))而不是空格,在檢索時(shí)也不會(huì)去掉填充值(這是特別需要注意的)。
MySQL在比較Binary字符串時(shí),每次按一個(gè)字節(jié),并且是根據(jù)該字節(jié)的數(shù)值進(jìn)行比較;因此二進(jìn)制比較比字符串的比較快。
3.3 BLOB和TEXT類(lèi)型
BLOB和TEXT都是為存儲(chǔ)很大的數(shù)據(jù)而設(shè)計(jì)的,分別采用二進(jìn)制和字符方式存儲(chǔ),都是變長(zhǎng)字符串類(lèi)型。
實(shí)際上它們屬于不同的數(shù)據(jù)類(lèi)型家族:字符類(lèi)型是TINYTEXT、SMALLTEXT、TEXT、MEDIUMTEXT、LONGTEXT,對(duì)應(yīng)的二進(jìn)制類(lèi)型是 TINYBLOB、SMALLBLOB、BLOB、MEDIUMBLOB、LONGBLOB。BLOB和SMALLBLOB是同義詞,TEXT和SMALLTEXT是同義詞。
與其他類(lèi)型不同,每個(gè)BLOB和TEXT值會(huì)被當(dāng)成獨(dú)立的對(duì)象對(duì)象。當(dāng)數(shù)據(jù)很大時(shí),InnoDB會(huì)專(zhuān)門(mén)使用“外部”存儲(chǔ)區(qū)域存儲(chǔ),此時(shí)每個(gè)值在行內(nèi)需要1~4個(gè)字節(jié)存儲(chǔ)一個(gè)指針,然后在外部存儲(chǔ)區(qū)域存儲(chǔ)實(shí)際的值。
BLOB和TEXT家族的僅有不同是BLOB類(lèi)型存儲(chǔ)的是二進(jìn)制數(shù)據(jù),沒(méi)有排序規(guī)則或者字符集,而TEXT類(lèi)型有字符集和排序規(guī)則。
MySQL只會(huì)對(duì)BLOB和TEXT列中最前max_sort_length字節(jié)進(jìn)行排序,而不是整個(gè)字符串。如果只排序前面一小部分字符,則可以減小max_sort_length的值,或者使用order by substring(列名,length)。
MYSQL不能將BLOB和TEXT列全部長(zhǎng)度字符串進(jìn)行索引,也不能用這些索引消除排序。
3.3 ENUM類(lèi)型
有時(shí)可以使用ENUM代替常用的字符串類(lèi)型。枚舉列可以把一些不重復(fù)的字符串存儲(chǔ)成一個(gè)預(yù)定義的集合。
ENUM的存儲(chǔ)非常緊湊,會(huì)根據(jù)列表值的數(shù)量壓縮到一個(gè)或兩個(gè)字節(jié)中。
ENUM在內(nèi)部會(huì)將每個(gè)值在列表中的位置保存為整數(shù),并且在表的.frm文件中保存“數(shù)字-字符串”映射關(guān)系的“查找表”。
如下案例:
-- 創(chuàng)建表 CREATE TABLE enum_test( e enum('fish','apple','dog') NOT NULL ) -- 插入枚舉數(shù)據(jù) INSERT INTO enum_test (e) VALUES('fish'),('dog'),('apple');
測(cè)試實(shí)際存儲(chǔ)的是數(shù)字:
select e+0 from enum_test;
結(jié)果如下:
枚舉字段支持同時(shí)采用字符串和數(shù)值進(jìn)行判斷和計(jì)算,如上面的sql,比如和數(shù)值類(lèi)型進(jìn)行比較。采用數(shù)值時(shí),使用的枚舉字段的排序值,排序值從1開(kāi)始!
需要注意的是,枚舉字段是按照內(nèi)部存儲(chǔ)的整數(shù)而不是定義的字符串進(jìn)行排序的!
一種繞過(guò)這種限制的方式是按照需要的順序來(lái)定義枚舉列的值,另外也可以使用FIELD()函數(shù)顯式的指定排序順序,但這會(huì)導(dǎo)致MySQL無(wú)法利用索引消除排序。
枚舉的字符串列表是固定的,添加或者刪除枚舉字符串必須使用ALTER TABLE這樣的DDL語(yǔ)句,因此對(duì)于未來(lái)可能會(huì)改變的字符串,使用枚舉不是一個(gè)好主意。
由于MySQL把每一個(gè)枚舉值保存為整數(shù),在檢索時(shí)必須進(jìn)行額外的查找才能轉(zhuǎn)換為字符串,所以會(huì)有一定的開(kāi)銷(xiāo)。
4 日期和時(shí)間類(lèi)型
MySQL有很多日期和時(shí)間類(lèi)型,比如DATE、DATETIME、TIMESTAMP、TIME、YEAR??梢源鎯?chǔ)的最小時(shí)間粒度是秒。
DATETIME類(lèi)型能保存大范圍的值,從1001年~9999年,精度為秒,占8個(gè)字節(jié)的長(zhǎng)度。它將時(shí)間格式封裝為YYYYMMDDHHMMSS的整數(shù)中,與時(shí)區(qū)無(wú)關(guān)。默認(rèn)情況下,MySQL以一種可排序的格式顯示DATETIME值,比如“2019-11-12 13:56:45”。
TIMESTAMP類(lèi)型的存儲(chǔ)的是1970年1月1日午夜以來(lái)的秒數(shù)(格林威治標(biāo)準(zhǔn)時(shí)間),只使用了4個(gè)字節(jié)的存儲(chǔ)空間,因此它的范圍比DATETIME小得多:1970年~2038年。
TIMESTAMP列會(huì)默認(rèn)設(shè)置為Not null屬性,所以在插入數(shù)據(jù)時(shí),若不給值就會(huì)默認(rèn)為當(dāng)前時(shí)間戳。
目前,MySQL沒(méi)有提供合適的數(shù)據(jù)類(lèi)型以存儲(chǔ)比秒更小粒度的日期和時(shí)間格式,但可以使用其他方法,比如使用BIGINT存儲(chǔ)微秒級(jí)別的時(shí)間戳,比如用DOUBLE存儲(chǔ)秒之后的小數(shù)部分。
5 位數(shù)據(jù)類(lèi)型
MySQL的所有位類(lèi)型,不管底層存儲(chǔ)和處理方式如何,從技術(shù)上來(lái)說(shuō)都是字符串類(lèi)型。常見(jiàn)位數(shù)據(jù)類(lèi)型是BIT和SET。
在MySQL5.0之前,BIT是TINYINT的同義詞,但5.0之后有了新的含義。
BIT(1)表示一個(gè)包含單個(gè)位的字段,BIT(2)則表示兩個(gè)位的字段,最大長(zhǎng)度為64位。
不同的存儲(chǔ)引擎對(duì)BIT 有不同的存儲(chǔ)方式。MyISAM會(huì)打包存儲(chǔ)所有BIT列,比如17個(gè)單獨(dú)的BIT列只需要17位存儲(chǔ),只需要3個(gè)字節(jié)的空間。而Memory和InnoDB等存儲(chǔ)引擎,則是為每個(gè)BIT列使用一個(gè)足夠存儲(chǔ)的最小整數(shù)類(lèi)型來(lái)存放,所以不能節(jié)省存儲(chǔ)空間。
注意,MySQL將BIT當(dāng)作字符串類(lèi)型,而不是數(shù)字類(lèi)型。如果檢索BIT(1)的值時(shí),結(jié)果是一個(gè)包含二進(jìn)制0或1的字符串,而不是ASCII碼的“0”或“1”。然而,在數(shù)字上下文中檢索時(shí),結(jié)果將是字符串轉(zhuǎn)換成的數(shù)字。比如存儲(chǔ)一個(gè)值為b‘00111001’(等于十進(jìn)制57)到BIT(8)的列并直接檢索它,得到的內(nèi)容是“00111001,而如果檢索的內(nèi)容是“列+0”,那么得到的值是57。
如下案例:
CREATE TABLE `bits` ( `bitss` bit(8) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; INSERT INTO `bits`(`bitss`) VALUES (b'00111001'); INSERT INTO `bits`(`bitss`) VALUES (b'111');
使用如下查詢(xún):
select bitss,bitss+0 from bits
結(jié)果如下:
位類(lèi)型的常見(jiàn)用法是:如果需要位一條數(shù)據(jù)保存許多true/false值,則可合并這些列到一個(gè)SET數(shù)據(jù)類(lèi)型的列。
6 選擇優(yōu)化的數(shù)據(jù)類(lèi)型
MySQL支持的數(shù)據(jù)類(lèi)型非常多,選擇正確的數(shù)據(jù)類(lèi)型對(duì)于獲得高性能至關(guān)重要,不管存儲(chǔ)哪種數(shù)據(jù)類(lèi)型,下面幾個(gè)簡(jiǎn)單的原則都有助于做出更好的選擇!
- 更小的通常更好。一般情況下,應(yīng)該盡量使用可以正確存儲(chǔ)數(shù)據(jù)的最小數(shù)據(jù)類(lèi)型,因?yàn)樗鼈冋几俚拇疟P(pán),內(nèi)存和CPU緩存,處理時(shí)需要的CPU周期也更少。
- 簡(jiǎn)單就好。簡(jiǎn)單數(shù)據(jù)類(lèi)型的操作通常需要更少的CPU周期,例如,整形比字符操作代價(jià)更低,因?yàn)樽址托?duì)規(guī)則(排序規(guī)則)是字符比較比整形比較更復(fù)雜。比如,使用MySQL內(nèi)建類(lèi)型(date、time、datetime)而不是字符串來(lái)存儲(chǔ)日期和時(shí)間,另外一個(gè)是用整型來(lái)存儲(chǔ)IP地址。
- 盡量避免NULL。通常在定義表字段時(shí),如果沒(méi)有指定列為NOT NULL,默認(rèn)都是允許為NULL的。
- 如果查詢(xún)中包含可為NULL的列,對(duì)MySQL來(lái)說(shuō)更難優(yōu)化,因?yàn)榭蔀镹ULL的列使得索引、索引統(tǒng)計(jì)和值的比較都更復(fù)雜。可為NULL的列會(huì)占用更多的存儲(chǔ)空間,當(dāng)可為NULL的列被索引時(shí),每個(gè)索引記錄需要一個(gè)額外的字節(jié),在MyISAM里甚至還可能導(dǎo)致固定大小的索引(例如只有一個(gè)整數(shù)列的索引)變成可變大小的索引。
- 通常情況下最好指定列為NOT NULL,但一般把可為NULL的列改為NOT NULL帶來(lái)的性能提升比較小,所以在調(diào)優(yōu)時(shí),沒(méi)有必要首先對(duì)此下手。
- 但是對(duì)于NULL有一個(gè)例外是,InnoDB僅會(huì)使用單獨(dú)的位(bit)存儲(chǔ)NULL值(即是否為NULL的標(biāo)記位),因此NULL值所以對(duì)于稀疏數(shù)據(jù)(大部分?jǐn)?shù)據(jù)為NULL,只有少部分非NULL的數(shù)據(jù))有很好的空間效率,但這不使適于MyISAM。
6.1 特殊的數(shù)據(jù)類(lèi)型
IPv4地址經(jīng)常被人用varchar(15)來(lái)存儲(chǔ),但是它實(shí)際上是一個(gè)32位無(wú)符號(hào)的整數(shù),不是字符串,小數(shù)點(diǎn)將地址分四段的表示方式只是為了讓人容易閱讀,所以應(yīng)該用無(wú)符號(hào)整型來(lái)存儲(chǔ)IP地址(如果不使用無(wú)符號(hào)INT,則長(zhǎng)度不夠),MYSQL用INET_ATON() 和INET_NTOA()用于這兩種表示轉(zhuǎn)換。
- 將IP地址轉(zhuǎn)換為整型可以使用
select inet_aton(ip) from xxx;
- 將整型轉(zhuǎn)換為IP地址可以使用
select inet_ntoa(intip) from xxx;
到此這篇關(guān)于深入理解MySQL數(shù)據(jù)類(lèi)型的選擇優(yōu)化的文章就介紹到這了,更多相關(guān)MySQL數(shù)據(jù)選擇優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mysql聯(lián)表update數(shù)據(jù)的示例詳解
這篇文章主要介紹了Mysql聯(lián)表update數(shù)據(jù)的示例詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11MySQL中實(shí)現(xiàn)分頁(yè)操作的實(shí)戰(zhàn)指南
MySQL的分頁(yè)似乎一直是個(gè)問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于MySQL中實(shí)現(xiàn)分頁(yè)操作的相關(guān)資料,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08springboot啟動(dòng)404問(wèn)題以及解決方案
這篇文章主要介紹了springboot啟動(dòng)404問(wèn)題以及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01