數(shù)字類型
MySQL 支持標(biāo)準(zhǔn) SQL 中所有數(shù)據(jù)類型。
所有的這些類型包括:
- 精確的數(shù)據(jù)類型:INTEGER,SMAILLINT,DECIMAL,NUMERIC;
- 近似的數(shù)據(jù)類型:FLOAT,REAL,DOUBLE PRECISION;
關(guān)鍵字 INT 是 INTEGER 的別名,關(guān)鍵字 DEC 和 FIXED 是 DECIMAL的別名。
在 MyISAM/MEMORY/InnoDB和NDB表中支持BIT 數(shù)據(jù)類型,BIT 數(shù)據(jù)類型用于存儲(chǔ) bit 值。
整型
MySQL 支持 SQL 標(biāo)準(zhǔn)整數(shù)類型INTEGER(或INT)和SMAILLINT。在此之外,MySQL 還擴(kuò)展了數(shù)據(jù)類型:TINYINT、MEDIUMINT、BIGINT。下表顯示了每種整數(shù)類型所需的存儲(chǔ)空間和范圍。
類型 | 存儲(chǔ)空間(字節(jié)) | 最小值(signed) | 最大值(signed) | 最小值(unsigned) | 最大值(unsigned) |
---|---|---|---|---|---|
tinyint | 1 | -2^7 | 2^7-1 | 0 | 2^8-1 |
smallint | 2 | -2^15 | 2^15-1 | 0 | 2^16-1 |
meduimint | 3 | -2^23 | 2^23-1 | 0 | 2^24-1 |
int | 4 | -2^31 | 2^31-1 | 0 | 2^32-1 |
bigint | 8 | -2^63 | 2^63-1 | 0 | 2^64-1 |
精確小數(shù)類型
DECIMAL 和 NUMERIC 類型是精確類型。比如貨幣,需要使用精確類型存儲(chǔ)。在MySQL中用DECIMAL實(shí)現(xiàn)了NUMERIC,所在下文中有關(guān)DECIMAL的描述對(duì)NUMERIC也適用。MySQL使用二進(jìn)制存儲(chǔ)DECIMAL的值。
在小數(shù)列聲明中,精度和小數(shù)位數(shù)可以(通常是)指定:salary DECIMAL(5,2)
在本例中,5表示數(shù)字個(gè)數(shù)(不含小數(shù)點(diǎn)),2表示小數(shù)點(diǎn)后的位數(shù)。本例中的數(shù)據(jù)范圍是:-999.99至999.99。
在標(biāo)準(zhǔn) SQL 中當(dāng)為精度為0時(shí)可以省略,即DEMICAL(5)等同于DEMICAL(5,0)。
近似小數(shù)類型
FLOAT和DOUBLE類型表示近似的數(shù)值數(shù)據(jù)值。MySQL使用四個(gè)字節(jié)作為單精度值,八個(gè)字節(jié)作為雙精度值。
BIT數(shù)據(jù)類型
BIT(M) 允許存儲(chǔ)M個(gè)BIT值,M的范圍是1至64。
數(shù)字類型屬性
MySQL支持一個(gè)擴(kuò)展,用于根據(jù)類型的基本關(guān)鍵字在圓括號(hào)中指定整數(shù)數(shù)據(jù)類型的顯示寬度。例如,INT(4)指定一個(gè)顯示寬度為四位的INT。
這個(gè)可選的顯示寬度可以被應(yīng)用程序用來(lái)顯示寬度小于為該列指定的寬度的整數(shù)值,方法是用空格填充它們。(也就是說(shuō),這個(gè)寬度出現(xiàn)在結(jié)果集返回的元數(shù)據(jù)中,無(wú)論是否使用都取決于應(yīng)用程序。)
顯示寬度不限制可以存儲(chǔ)在列中的值的范圍,也不會(huì)阻止比列顯示寬度更寬的值被正確顯示。
所有的整數(shù)類型都可以有一個(gè)可選的(非標(biāo)準(zhǔn)的)UNSIGNED,當(dāng)你需要更大的范圍時(shí)可供選擇。同樣的浮點(diǎn)類型(精確,非精確)也可以使用 UNSIGNED,但是與整型不同的是,浮點(diǎn)型的 UNSIGNED 不會(huì)改變數(shù)據(jù)的范圍。
超出范圍和溢出處理
當(dāng)存儲(chǔ)的值超出額定范圍后,存儲(chǔ)的結(jié)果視MySQL的模式?jīng)Q定。
當(dāng)啟用了嚴(yán)格模式,則會(huì)按照標(biāo)準(zhǔn)的SQL拒絕數(shù)據(jù)的寫入。若未啟用嚴(yán)格模式,則將數(shù)據(jù)裁剪并寫入。
日期類型
DATE, DATETIME, TIMESTAMP
DATE, DATETIME, TIMESTAMP 是互相關(guān)聯(lián)的。這章節(jié)將會(huì)闡述,它們哪些點(diǎn)是相同的,另外又有哪些點(diǎn)是有差異的。
DATE 日期類型用于具有日期部分但沒有時(shí)間部分的值。MySQL以'YYYY-MM-DD'格式檢索并顯示日期值,支持的范圍是'1000-01-01' 到 '9999-12-31'。
DATETIME 同時(shí)有日期部分和時(shí)間部分。MySQL 以'YYYY-MM-DD HH:MM:SS'的格式,支持的范圍從'1000-01-01 00:00:00' 到 '9999-12-31 23:59:59'。
TIMESTAMP 也同時(shí)有日期部分和時(shí)間部分。它的范圍是:'1970-01-01 00:00:01' UTC 到 '2038-01-19 03:14:07' UTC。
DATETIME 和 TIMESTAMP 精確到微秒。
DATETIME 和 TIMESTAMP 數(shù)據(jù)類型具備自動(dòng)初始化和更新功能(舉例:業(yè)務(wù)上通常需要的創(chuàng)建時(shí)間和更新時(shí)間,在MySQL層面上可以自動(dòng)完成)。
對(duì)應(yīng) TIMESTAMP 類型,存儲(chǔ)時(shí)會(huì)自動(dòng)轉(zhuǎn)到 UTC 時(shí)區(qū),在檢索時(shí)則會(huì)自動(dòng)從 UTC時(shí)區(qū)轉(zhuǎn)到當(dāng)前時(shí)區(qū)。( DATETIME不會(huì)執(zhí)行該操作)。默認(rèn)情況下,每個(gè)連接的當(dāng)前時(shí)區(qū)是服務(wù)器的時(shí)間。時(shí)區(qū)可以在每個(gè)連接的基礎(chǔ)上設(shè)置。只要時(shí)區(qū)設(shè)置保持不變,您將獲得與您存儲(chǔ)的值相同的值。如果您存儲(chǔ) TIMESTAMP ,然后更改時(shí)區(qū)并檢索該值,則檢索到的值與您存儲(chǔ)的值不同。發(fā)生這種情況是因?yàn)橥粫r(shí)區(qū)未用于雙向轉(zhuǎn)換。當(dāng)前時(shí)區(qū)的修改參見系統(tǒng)變量:time_zone。
MySQL 允許指定為字符串的值的“寬松”格式,其中任何標(biāo)點(diǎn)符號(hào)可用作日期部分或時(shí)間部分之間的分隔符。雖然 MySQL 提供了寬松的存儲(chǔ)環(huán)境,我們最好仍按照默認(rèn)的格式進(jìn)行編碼,以避免可讀性差引起的干擾。
TIME
TIME 以HH:MM:SS
或HHH:MM:SS
格式化數(shù)據(jù)。TIME 的范圍從 '-838:59:59' 到 '838:59:59'。小時(shí)部分如此大的原因是,TIME并不是只用于1天內(nèi)的場(chǎng)景。也可能用于兩次事件間的間隔事件,這可能遠(yuǎn)大于24小時(shí)。
當(dāng)錄入的值超出范圍后,將會(huì)自動(dòng)剪切到最近的有效范圍內(nèi)的值。
YEAR
YEAR 以 YYYY
格式,范圍從 1901 至 2155,或 0000。
若是4位則范圍是,1901~2155。
若是錄入199,則169轉(zhuǎn)化為2001-2069,7099則轉(zhuǎn)化為19701999。
若是錄入數(shù)字0,則轉(zhuǎn)化為0000。若是錄入字符0或00,則轉(zhuǎn)化為2000。
關(guān)于MySQL默認(rèn)值了解即可(不能依賴默認(rèn)值),我們需要嚴(yán)格控制錄入的值。
在 MySQL 5.7 中已經(jīng)禁用了YEAR(2);
自動(dòng)初始化和更新 TIMESTAMP 與 DATETIME
表格中的 TIMESTAMP 或 DATETIME 的列可以初始化當(dāng)前時(shí)間作為默認(rèn)值,或設(shè)置為修改自動(dòng)更新,或兩者共存。
- 當(dāng)指定的列中沒有值時(shí),使用當(dāng)前時(shí)間作為默認(rèn)時(shí)間。
- 當(dāng)該行中任何其他列的值從其當(dāng)前值更改時(shí),自動(dòng)更新的列會(huì)自動(dòng)更新為當(dāng)前時(shí)間戳。
要設(shè)置自動(dòng)更新屬性時(shí),在列的定義時(shí)使用以下語(yǔ)句(順序不相關(guān)):
DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
CURRENT_TIMESTAMP
有以下的同義詞: CURRENT_TIMESTAMP(), NOW(), LOCALTIME, LOCALTIME(), LOCALTIMESTAMP, 和 LOCALTIMESTAMP()。
要 MySQL 5.7中,新增
DATETIME
列的支持設(shè)置默認(rèn)值和自動(dòng)更新。在之前的版本,你如果嘗試設(shè)置將會(huì)得到一個(gè)錯(cuò)誤。
字符串類型
CHAR VARCHAR
字符串類型CHAR
, VARCHAR
, BINARY
, VARBINARY
, BLOB
, TEXT
, ENUM
,和 SET
。
CHAR和VARCHAR類型相似,但它們被存儲(chǔ)和檢索的方式不同。它們的最大長(zhǎng)度和尾部空格是否保留也不同。
CHAR
列長(zhǎng)度可以是0到255之間的任何值。CHAR
存儲(chǔ)值時(shí),它們將空格填充到指定的長(zhǎng)度。當(dāng)CHAR
檢索到值時(shí),除非PAD_CHAR_TO_FULL_LENGTH
啟用了SQL模式,否則將刪除尾隨空格 。
VARCHAR列中的 值是可變長(zhǎng)度的字符串。長(zhǎng)度可以指定為0到65535之間的值。
與CHAR不同,VARCHAR會(huì)存儲(chǔ)一個(gè)長(zhǎng)度為1字節(jié)或2字節(jié)的前綴,用于存儲(chǔ)長(zhǎng)度值,用以表明存儲(chǔ)的字節(jié)數(shù)。
若需存儲(chǔ)的字節(jié)數(shù)少于255,則前綴的長(zhǎng)度為1。
否則,前綴的長(zhǎng)度為2。
以下表格說(shuō)明 CHAR 和 VARCHAR 在存儲(chǔ)值時(shí)候的差異:
顯示為存儲(chǔ)在表格最后一行的值僅適用 于不使用嚴(yán)格模式的情況 ; 如果MySQL在嚴(yán)格模式下運(yùn)行,則超出列長(zhǎng)度的值不會(huì)被存儲(chǔ),并會(huì)導(dǎo)致錯(cuò)誤。
這些特性會(huì)很有用:
- 比如在列的可選值是 Y/N時(shí),選擇CHAR(1)比VARCHAR(1)節(jié)省一個(gè)字節(jié)空間。
- 比如既有的數(shù)據(jù)中存在一些以空格結(jié)尾的數(shù)據(jù),那么可以先將列改為CHAR保存。然后再修改為VARCHAR。
BINARY VARBINARY
BINARY和VARBINARY類型與CHAR和VARCHAR相似,除了它們包含二進(jìn)制字符串而非非二進(jìn)制字符串。也就是說(shuō),它們包含字節(jié)串而不是字符串。
BINARY的填充字節(jié)是0x00。字節(jié)在比較中很重要,包括ORDER BY
與DISTINCT
操作。0x00與空格在比較時(shí)是不一樣的,0x00要小于空格。
如果您打算使用BINARY數(shù)據(jù)類型來(lái)存儲(chǔ)二進(jìn)制數(shù)據(jù),并且您要求檢索到的值與存儲(chǔ)的值完全相同,那么您應(yīng)該仔細(xì)考慮前面的填充和剝離特征 。
TEXT BLOB
BLOB 是二進(jìn)制字符串。
它有四個(gè)BLOB 類型TINYBLOB,BLOB, MEDIUMBLOB,和LONGBLOB。
TEXT 是非二進(jìn)制字符串
它有四個(gè)TEXT類型 TINYTEXT,TEXT, MEDIUMTEXT,和LONGTEXT。
對(duì)于TEXT和BLOB列,插入時(shí)沒有填充,并且在select時(shí)沒有字節(jié)被刪除。
以下是使用這兩者的限制點(diǎn):
- 使用臨時(shí)表處理的查詢結(jié)果中的 實(shí)例
BLOB
或TEXT
列導(dǎo)致服務(wù)器在磁盤上而不是在內(nèi)存中使用表,因?yàn)?MEMORY
存儲(chǔ)引擎不支持這些數(shù)據(jù)類型(請(qǐng)參見 第8.4.4節(jié)“內(nèi)部臨時(shí)在MySQL中使用表“)。使用磁盤會(huì)導(dǎo)致性能損失,因此只有在確實(shí)需要時(shí)才在查詢結(jié)果中包含BLOB
或TEXT
列。例如,避免使用SELECT *
,它會(huì)選擇所有列。 -
max_sort_length
排序時(shí)僅使用列 的第一個(gè) 字節(jié)。缺省值為max_sort_length
1024.通過(guò)增加max_sort_length
服務(wù)器啟動(dòng)或運(yùn)行時(shí)的值,可以在排序或分組中增加更多字節(jié) 。任何客戶端都可以更改其會(huì)話max_sort_length
變量的值:
mysql> SET max_sort_length = 2000;
mysql> SELECT id, comment FROM t
-> ORDER BY comment;
ENUM
枚舉是一個(gè)字符串對(duì)象,其值是從表創(chuàng)建時(shí)列規(guī)范中顯式枚舉的允許值列表中選擇的值。
它有以下的好處:
- 緊湊的存儲(chǔ)特性,字符串會(huì)被映射為數(shù)字存儲(chǔ);
- 良好的可讀性;
真實(shí)場(chǎng)景下很少用到?
SET
SET 由0~64個(gè)以,
分隔的字符串構(gòu)成的,要注意成員值本身是不包含逗號(hào)的。關(guān)于64的限制,參考Section C.10.5, “Limits Imposed by .frm File Structure”
。
若在SET中出現(xiàn)重復(fù)值,則會(huì)產(chǎn)生警告。(若開啟嚴(yán)格模式,則是直接拋異常)。SET字符串尾部的空格將會(huì)自動(dòng)被移除。
數(shù)據(jù)類型默認(rèn)值
除了一個(gè)例外情況外,默認(rèn)值都必須是常量;它不可以是方法或者表達(dá)式;這意味著,你不能設(shè)置日期類型的列設(shè)置默認(rèn)值為:NOW()
或CURRENT_DATE
。
截止MySQL5.7唯一的例外情況是,你可以設(shè)置日期類型的列默認(rèn)值為:CURRENT_TIMESTAMP
。
BLOB、TEXT、JSON、GEOMETRY的列不能設(shè)置默認(rèn)值;
如果列中沒有指定明確的默認(rèn)值,則MySQL的默認(rèn)值規(guī)則如下:
- 如果列中允許
NULL
值,則默認(rèn)值為NULL
- 如果列中不允許
NULL
值,則MySQL不指定默認(rèn)值;
當(dāng)一個(gè)明確表明為NOT NULL的列,被INSERT或者UPDATE的數(shù)據(jù)為NULL時(shí)。MySQL則根據(jù)對(duì)應(yīng)模式進(jìn)行處理:
- 如果啟用嚴(yán)格模式,則將拋出異常并回滾事務(wù);
- 如果未啟用嚴(yán)格模式,MySQL將列設(shè)置為列數(shù)據(jù)類型的隱式默認(rèn)值。
舉例,假定創(chuàng)建數(shù)據(jù)庫(kù)表如下:
CREATE TABLE t (i INT NOT NULL);
INSERT INTO t VALUES();
INSERT INTO t VALUES(DEFAULT);
INSERT INTO t VALUES(DEFAULT(i));
在本例中 i
沒有明確的默認(rèn)值。
- 當(dāng)啟用嚴(yán)格模式時(shí),三條指令均將拋出異常并回滾。
- 當(dāng)未啟用嚴(yán)格模式時(shí),僅第三條指令會(huì)拋出異常并回滾。前兩個(gè)語(yǔ)句插入隱式默認(rèn)值,但第三個(gè)失敗,因?yàn)槿笔≈担╥)不能產(chǎn)生值。
對(duì)于已存在的數(shù)據(jù)庫(kù)表,你可以使用SHOW CREATE TABLE
來(lái)顯示隱式的默認(rèn)值。
隱式默認(rèn)值定義如下:
- 對(duì)于數(shù)字類型其默認(rèn)值是:0;對(duì)于啟動(dòng)了自增序列的數(shù)字類型,則默認(rèn)值是下一個(gè)數(shù)值;
- 對(duì)于除了
TIMESTAMP
之外的日期類型,其默認(rèn)值是用0填充的字符串。比如:DATETIME
其默認(rèn)值是0000-00-00 00:00:00
。對(duì)于TIMESTAMP
的默認(rèn)值,則是當(dāng)前的時(shí)間戳對(duì)應(yīng)值。 - 對(duì)于除了枚舉類型之外的字符串值,其默認(rèn)值是空字符串;對(duì)于枚舉類型,其默認(rèn)值則是枚舉類型中的第一個(gè)值。
小知識(shí): SERIAL DEFAULT VALUE 是對(duì)應(yīng)數(shù)字類型下 NOT NULL AUTO_INCREMENT UNIQUE 的別名。
數(shù)據(jù)類型存儲(chǔ)要求
磁盤上表數(shù)據(jù)的存儲(chǔ)要求取決于幾個(gè)因素。不同的存儲(chǔ)引擎以不同方式存儲(chǔ)原始數(shù)據(jù)。表格數(shù)據(jù)可能會(huì)被壓縮,無(wú)論是列還是整行,都會(huì)使表或列的存儲(chǔ)需求計(jì)算復(fù)雜化。
盡管磁盤上的存儲(chǔ)布局有所不同,但內(nèi)部MySQL APIs使用了適用于所有存儲(chǔ)引擎的一致數(shù)據(jù)結(jié)構(gòu),通信并交換關(guān)于表行的信息。
本節(jié)包括MySQL支持的每個(gè)數(shù)據(jù)類型的存儲(chǔ)要求的指導(dǎo)方針和信息。
在MySQL內(nèi)部能夠支持的最大單行的大小是65535字節(jié),即便存儲(chǔ)引擎支持更大也不行。當(dāng)然這個(gè)數(shù)據(jù)不包括:BLOB、TEXT類型(對(duì)于 BLOB、TEXT 列而言,它只在65535中貢獻(xiàn)9至12字節(jié));對(duì)于 BLOB、TEXT類型,真實(shí)的數(shù)據(jù)內(nèi)容并不存儲(chǔ)在行緩沖區(qū)
,故它們的值所占用的內(nèi)存不受行緩沖區(qū)
的限制。不同的引擎存儲(chǔ)于分配數(shù)據(jù)的方式均有差異。
INNODB 存儲(chǔ)引擎
這部分內(nèi)容請(qǐng)直接參見Section 14.8.1.2, “The Physical Row Structure of an InnoDB Table”。
其他的存儲(chǔ)引擎,暫不展開;
選擇正確的列類型
為了優(yōu)化存儲(chǔ),你需要選擇最精確的數(shù)據(jù)類型;以范圍1~9999的整型數(shù)據(jù)為例,MEDIUMINT UNSIGNED
是最佳的選擇;既能滿足存儲(chǔ)需求,又可以使用最少的存儲(chǔ)量(參見上文的存儲(chǔ)字節(jié));
如果對(duì)精度不敏感,則使用DOUBLE
是不錯(cuò)的選擇;如果需要高精度,BIGINT
是不錯(cuò)的替代,這使您可以用64位整數(shù)進(jìn)行所有計(jì)算,然后根據(jù)需要將結(jié)果轉(zhuǎn)換回浮點(diǎn)值。
其它數(shù)據(jù)庫(kù)SQL與MySQL的類型對(duì)照表
提示:MySQL的正確的讀法是:My-S-Q-L,每個(gè)字母需要分開念,是不能將SQL連成單詞去讀。盡管大部門人都是連著讀的:)。