MySQL數據庫的表是一個二維表,由一個或多個數據列構成。每個數據列都有它的特定類型,該類型決定了MySQL如何看待該列數據,我們可以把整型數值存放到字符類型的列中,MySQL則會把它看成字符串來處理。MySQL中的列類型有三種:數值類、字符串類和日期/時間類。從大類來看列類型和數值類型一樣,都是只有三種。但每種列類型都還可細分。下面對各種列類型進行詳細介紹。
數值型的列類型包括整型和浮點型兩大類。
Table 1.2. 數值類數據列類型
MySQL有五種整型數據列類型,即TINYINT,SMALLINT,MEDIUMINT,INT和BIGINT。它們之間的區別是取值范圍不同,存儲空間也各不相同。在整型數據列後加上UNSIGNED屬性可以禁止負數,取值從0開始。
聲明整型數據列時,我們可以為它指定個顯示寬度M(1~255),如INT(5),指定顯示寬度為5個字符,如果沒有給它指定顯示寬度,MySQL會為它指定一個默認值。顯示寬度只用於顯示,並不能限制取值范圍和占用空間,如:INT(3)會占用4個字節的存儲空間,並且允許的最大值也不會是999,而是INT整型所允許的最大值。
MySQL有三種浮點型數據列類型,分別是:FLOAT,DOUBLE和DECIMAL。浮點類數據類型有一個最大可表示值和一個最小非零可表示值,最小非零可表示值決定了該類型的精確度。
MySQL 4.0.2版之後,FLOAT和DOUBLE都可以指定UNSIGNED屬性。當指定該屬性時,取值范圍不平移到正數區間,而只是簡單地把浮點類型的負數部份去掉。
浮點類型也有M(1~255)和D(1~30,且不能大於M-2)。分別表示顯示寬度和小數位數。M和D在FLOAT和DOUBLE中是可選的,默認,當MySQL版本大於3.23.6時,FLOAT和DOUBLE類型將被保存為硬件所支持的最大精度。DECIMAL的M和D值在MySQL3.23.6後可選,默認D值為0,M值為10。
為了節省存儲空間和提高數據庫處理效率,我們應根據應用數據的取值范圍來選擇一個最適合的數據列類型。如果把一個超出數據列取值范圍的數存入該列,則MySQL就會截短該值,如:我們把99999存入SMALLINT(3)數據列裡,因為SMALLINT(3)的取值范圍是-32768~32767,所以就會被截短成32767存儲。顯示寬度3不會影響數值的存儲。只影響顯示。
對於浮點數據列,存入的數值會被該列定義的小數位進行四捨五入。如把一個1.234存入FLOAT(6.1)數據列中,結果是1.2。
DECIMAL與FLOAT和DOUBLE的區別是:DECIMAL類型的值是以字符串的形式被儲存起來的,它的小數位數是固定的。它的優點是,不會象FLOAT和DOUBLE類型數據列那樣進行四捨五入而產生誤差,所以很適合用於財務計算;而它的缺點是:由於它的存儲格式不同,CPU不能對它進行直接運算,從而影響運算效率。DECIMAL(M,D)總共要占用M+2個字節。
ZEROFILL屬性適用於所有數值類數據列類型,作用是,如果數值的寬度小於定義的顯示寬度,則在數值前填充0。
UNSIGNED屬性不允許數據列出現負數。
AUTO_INCREMENT屬性可生成獨一無二的數字序列。只對整數類的數據列有效。
NULL和NOT NULL屬性設置數據列是否可為空。
DEFAULT屬性可為數據列指定默認值。
字符串可以用來表示任何一種值,所以它是最基本的類型之一。我們可以用字符串類型來存儲圖象或聲音之類的二進制數據,也可存儲用gzip壓縮的數據。下表介紹了各種字符串類型:
Table 1.3. 字符串類數據列類型
L+1、L+2是表示數據列是可變長度的,它占用的空間會根據數據行的增減面則改變。數據行的總長度取決於存放在這些數據列裡的數據值的長度。L+1或L+2裡多出來的字節是用來保存數據值的長度的。在對長度可變的數據進行處理時,MySQL要把數據內容和數據長度都保存起來。
如果把超出字符串最大長度的數據放到字符類數據列中,MySQL會自動進行截短處理。
ENUM和SET類型的數據列定義裡有一個列表,列表裡的元素就是該數據列的合法取值。如果試圖把一個沒有在列表裡的值放到數據列裡,它會被轉換為空字符串(“”)。
字符串類型的值被保存為一組連續的字節序列,並會根據它們容納的是二進制字符串還是非二進制字符而被區別對待為字節或者字符:
二進制字符串被視為一個連續的字節序列,與字符集無關。MySQL把BLOB數據列和帶BINARY屬性的CHAR和VARCHAR數據列裡的數據當作二進制值。
非二進制字符串被視為一個連續排列的字符序列。與字符集有關。MySQL把TEXT列與不帶BINARY屬性的CHAR和VARCHAR數據列裡的數據當作二進制值對待。
在MySQL4.1以後的版本中,不同的數據列可以使用不同的字符集。在MySQL4.1版本以前,MySQL用服務器的字符集作為默認字符集。
非二進制字符串,即我們通常所說的字符串,是按字符在字符集中先後次序進行比較和排序的。而二進制字符串因為與字符集無關,所以不以字符順序排序,而是以字節的二進制值作為比較和排序的依據。下面介紹兩種字符串的比較方式:
二進制字符串的比較方式是一個字節一個字節進行的,比較的依據是兩個字節的二進制值。也就是說它是區分大小寫的,因為同一個字母的大小寫的數值編碼是不一樣的。
非二進制字符串的比較方式是一個字符一個字符進行的,比較的依據是兩個字符在字符集中的先後順序。在大多數字符集中,同一個字母的大小寫往往有著相同的先後順序,所以它不區分大小寫。
二進制字符串與字符集無關,所以無論按字符計算還是按字節計算,二進制字符串的長度都是一樣的。所以VARCHAR(20)並不表示它最多能容納20個字符,而是表示它最多只能容納可以用20個字節表示出來的字符。對於單字節字符集,每個字符只占用一個字節,所以這兩者的長度是一樣的,但對於多字節字符集,它能容納的字符個數肯定少於20個。
CHAR和VARCHAR是最常用的兩種字符串類型,它們之間的區別是:
CHAR是固定長度的,每個值占用相同的字節,不夠的位數MySQL會在它的右邊用空格字符補足。
VARCHAR是一種可變長度的類型,每個值占用其剛好的字節數再加上一個用來記錄其長度的字節即L+1字節。
CHAR(0)和VARCHAR(0)都是合法的。VARCHAR(0)是從MySQL4.0.2版開始的。它們的作用是作為占位符或用來表示各種on/off開關值。
如何選擇CHAR和VARCHAR,這裡給出兩個原則:
如果數據都有相同的長度,選用VARCHAR會多占用空間,因為有一位用來存儲其長度。如果數據長短不一,選用VARCHAR能節省存儲空間。而CHAR不論字符長短都需占用相同的空間,即使是空值也不例外。
如果長度出入不大,而且是使用MyISAM或ISAM類型的表,則用CHAR會比VARCHAR好,因為MyISAM和ISAM類型的表對處理固定長度的行的效率高。
BLOB是二進制字符串,TEXT是非二進制字符串。兩者都可存放大容量的信息。
有關BLOB和TEXT索引的建立:
BDB表類型和MySQL3.23.2以上版本的MyISAM表類型允許在BLOB和TEXT數據列上建立索引。
ISAM、HEAP和InnoDB表不支持大對象列的索引。
使用BLOB和TEXT應注意的問題:
由於這兩個列類型所存儲的數據量大,所以刪除和修改操作容易在數據表裡產生大量的碎片,需定期運行OPTIMIZE TABLE以減少碎片和提高性能。
如果使用的值非常巨大,就需對服務器進行相應的優化調整,增加max_allowed_packet參數的值。對那些可會用到變些巨大數據的客戶程序,也需加大它們的數據包大小。
ENUM和SET都是比較特殊的字符串數據列類型,它們的取值范圍是一個預先定義好的列表。ENUM或SET數據列的取值只能從這個列表中進行選擇。ENUM和SET的主要區別是:
ENUM只能取單值,它的數據列表是一個枚舉集合。它的合法取值列表最多允許有65535個成員。例如:ENUM("N","Y")表示,該數據列的取值要麼是"Y",要麼就是"N"。
SET可取多值。它的合法取值列表最多允許有64個成員。空字符串也是一個合法的SET值。
ENUM和SET的值是以字符串形式出現的,但在內部,MySQL以數值的形式存儲它們。
ENUM的合法取值列表中的字符串被按聲明定義的順序被編號,從1開始。
SET的編號不是按順序進行編號的,SET中每一個合法取值都對應著SET值裡的一個位。第一個合法取值對應0位,第二個合法取值對應1位,以此類推,如果數值形式的SET值等於0,則說明它是一個空字符串,如果某個合法的取值出現在SET數據列裡,與之對應的位就會被置位;如果某個合法的取值沒有出現在SET數據列裡,與之對應的位就會被清零。正因為SET值與位有這樣的對應關系,所以SET數據列的多個合法取值才能同時出現並構成SET值。
在MySQL 4.1以前的版本,字符串數據列的字符集由服務器的字符決定,MySQL 4.1版以後的版本可對每個字符串數據列指定不同的字符串。如果按默認方式設置,可按數據列、數據表、數據庫、服務器的順序關聯字符串的字符集,直到找一個明確定義的字符集。
MySQL的日期時間類型有:DATE,DATETIME,TIME,TIMESTAMP和YEAR,下表是這些類型的取值范圍和存儲空間要求:
Table 1.4. 日期,時間類型列
DATE、TIME和DATATIME類型分別存放日期值、時間值、日期和時間值的組合。它們的格式分別是“CCYY-MM-DD”、“hh:mm:ss”、“CCYY-MM-DD hh:mm:ss”。
DATATIME裡的時間值和TIME值是有區別的,DATATIME裡的時間值代表的是幾點幾分,TIME值代表的是所花費的時間。當向TIME數據列插值時,需用時間的完整寫法,如12分30秒要寫成“00:12:30”。
TIMESTAMP數據列的格式是CCYYMMDDhhmmss,取值范圍從19700101000000開始,即1970年1月1號,最大到2037年。它的特點是能把數據行的創建或修改時間記錄下來:
如果把一個NULL值插入TIMESTAMP列,這個數據列就將自動取值為當前的日期和時間。
在創建和修改數據行時,如果沒有明確對TIMESTAMP數據列進行賦值,則它就會自動取值為當前的日期和時間。如果行中有多個TIMESTAMP列,只有第一個會自動取值。
如果對TIMESTAMP設置一個確定的日期和時間值,則會使TIMESTAMP的自動取值功能失效。
TIMESTAMP默認的列寬是14,可指定列寬,以改變顯示效果。但不論你指定的列寬如何,MySQL都是以4字節來存儲TIMESTAMP值,也總是以14位精度來計算。
如果需要把創建時間和最近一次修改時間同時記錄下來,可以用兩個時間戳來記錄,一個記錄創建時間,一個記錄修改時間。不過需記住兩件事,一是要把記錄修改時間的TIMESTAMP數據列放在最前面,這樣才會自動取值;二是創建一條新記錄時,要用now()函數來初始化創建時間TIMESTAMP數據列,這樣,該TIMESTAMP數據列就不會再變化。
YEAR是一種單字節的數據列類型,YEAR(4)的取值范圍是1901~2155,YEAR(2)的取值范圍是1970~2069,但只顯示最後兩位數。MySQL能自動把兩位數字年份轉換成四位數字的年份,如97和14分被轉換成1997和2014。轉換規則是這樣的:
年份值00~69將被轉換成2000~2069;
年份值70~99將被轉換成1970~1999。