数据库——字段类型

数据库的字段类型

今天对数据库中的一些数据类型进行总结。

MySQL数据类型选取的原则

(1)更小通常更好
一般情况下,应该尽量使用可以正确存储数据的最小数据类型。更小的数据类型通常更快,因为它们占用更少的磁盘、内存和CPU缓存,并且处理时需要的CPU周期也更少。
(2)简单更好
简单的数据类型的操作通常需要更少的CPU周期。例如整形比字符操作代价更低,因为字符集的校对规则(排序规则)使字符比较比整形比较更复杂。这里有两个例子:一个是应该使用MySQL内建的类型而不是字符串来存储日期和时间,另外一个是应该用整形存储IP地址。
(3)尽量避免NULL
很多表都包含可为NULL(空值)的列,即使应用程序并不需要保存NULL也是如此,这是因为可为NULL是列的默认属性。通常情况下最好指定列为NOT NULL,除非真的需要存储NULL值。
如果查询中包含可为NULL的列,对于MySQL来说更难优化,因为可为NULL的列使得索引、索引统计和值比较都更复杂。可为NULL的列会使用更多的存储空间,在MySQL中也需要特殊处理。当可为NULL的列被索引时,每个索引记录需要一个额外的字节,在MyISAM里甚至还可能导致固定大小的索引(例如一个整数列的索引)变成可变大小的索引。
通常把可为NULL的列改为NOT NULL带来的性能提升比较小,所以(调优时)没有必要首先在现有schema中查找并修改掉这种情况,除非确定这会导致问题。但是,如果计划在列上建索引,就应该尽量避免设计成可为NULL的列。
当然也有例外,例如值得一提的是,InnoDB使用单独的位(bit)存储NULL值,所以对于稀疏数据有很好的空间效率。这一点不适用于MyISAM。

数字类型

整数类型

有两种数字类型:整数(whole number)和实数(real number)。如果存储整数,可以使用这几种整数类型:TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT。分别使用9,16,24,32,64位存储空间。它们可以存储的值的范围是-2(N-1) 到2(N-1) -1,其中N是存储空间的位数。
整数类型有可选的UNSIGNED属性,表述不允许负值,这大致可以使正数的上限提高一倍。例如TINYINT.UNSIGNED可以存储的范围是0~255,而TINYINT的存储范围是-128 ~ 127.
注意: MySQL可以为整数指定宽度,例如INT(11),对大多数应用这是没有意义的:它不会限制值的合法范围,只是规定了MySQL的一些交互工具(例如MySQL 命令行客户端)用来显示字符的个数。对于存储和计算来说,INT(1)和INT(20)是相同的。

实数类型

实数是带有小数部分。除了存储小数部分,也可以使用Decimal存储比BIGINT还大的整数。MySQL即支持精确类型,也支持不精确类型。
FLOAT和DOUBLE类型支持使用标准的浮点运算进行近似计算。
DECIMAL类型用于存储精确的小数。在MySQL5.0和更高版本,DECIMAL支持精确计算。因为CPU不支持对DECIMAL的直接计算,所以在MySQL5.0以及更高版本中,MySQL服务自身实现了DECIMAL的高精度计算。

因为需要额外的空间和计算开销,所以应该尽量只对小数进行精确计算的时候才是用DECIMAL——例如存储财务数据。但在数据量比较大的时候,可以考虑使用BIGINT代替DECIMAL,将需要存储的货币单位根据小数的位数乘以相应的倍数即可。假设要存储财务数据精确到万分之一分,则可以把所有金额乘以一百五,然后将结果存储在BIGINT里,这样可以同时避免浮点存储计算不精确和DECIMAL精确计算代价高的问题。

字符串类型

VARCHAR

VARCHAR类型用于存储可变长字符串,是最常见的字符串数据类型。它比定长类型更节省空间,因为它仅适用必要的空间(例如,越短的字符串适用越少的空间)。有一种情况例外,如果MySQL表适用ROW_ROTMAT=FIXED创建的话,每一行都会使用定长存储,这会很浪费空间。

VARCHR需要使用1 或 2 个额外字节记录字符串的长度:如果列的最大长度小于或等于255字节,则只使用1个字节表示,否则使用2个字节。

适合使用VARCHAR的情况:
(1)字符串列的最大长度比平均长度达很多;
(2)列的更新很少,所以碎片不是问题;
(3)使用了像UTF-8这样复杂的字符集,每个字符都使用不同的字节数进行存储。

CHAR

CHAR类型是定长的:MySQL总是根据定长的字符串长度分配足够的为空间。
CHAR的适用场景
(1)CHAR使用存储很短的字符串,或者所有值都接近同一个长度。列如CHAR非常适合存储密码的MD5值,因为这是一个定长的值。
(2)对于经常变更的数据,CHAR也比VARCHAR更好,因为定长的CHAR类型不容易产生碎片。
(3)对于非常短的列,CHAR比VARCHAR在存储空间上也更有效率。例如CHAR(1)来存储只有Y和N的值,如果采用单字节字符集只需要一个字节,但是VARCHAR(1)确需要两个字节,因为还有一个额外记录长度的额外字节。

BINARY和VARBINARY

BINARY和VARBINARY存储的是二进制字符串。与CHAR和VARCHAR类似,分别存储定长和边长的二进制字符串。
使用场景:
当需要存储二进制数据,并且希望MySQL使用字节码而不是字符进行比较时,这些类型是非常有用的。二进制比较不仅仅体现在大小写敏感上。MySQL比较BINARY字符串时,每次按一个字节,并且根据该字节的值进行比较。因此二进制比较比字符串简单很多,所以也就更快。

使用VARCHAR(5)和VARCHAR(200)存储’hello’的空间开销是一样的。那么使用更短的列有什么优势吗?
事实证明有很大的优势。更长的列会消耗更多的内存,因为MySQL通常会分配固定大小的内存块来保存内部值。尤其是使用内存临时表进行排序或操作时会特别糟糕。在利用磁盘临时表进行排序时也同样糟糕。
所以最好的策略是只分配真正需要的空间。

BLOB和TEXT类型

BLOB和TEXT是为了存储很大的数据而设计的字符串数据类型,分别采用二进制和字符方式存储。
实际上,它们分别属于两组不同的数据类型家族:字符类型是TINYTEXT,SMALLTEXT,TEXT,MEDINUMTEXT,LONGTEXT;
对应的二进制类型是TINYBLOB,SMALLBLOB,BLOB,MEDIUMBLOB,LONGBLOB。BLOB是SMALLBLOB的同义词,TEXT是SMALLTEXT的同义词。

与其他类型不同MySQL把每个BLOB和TEXT值当作一个独立的对象处理。存储引擎在存储时通常会做特殊处理。当BLOB和TEXT值太大时,InnoDB 会使用专门的“外部”存储区域来进行存储,此时每个值在行内需要1~4个字节存储一个指针,然后在外部存储区域存储实际的值。

BLOB和TEXT家族之间仅有的不同是BLOB类型存储的是二进制数据,没有排序规则和字符集,而TEXT类型有字符集合排序规则。

MySQL对BLOB和TEXT列进行排序与其他类型是不同的:它只对每个列的最前max_sort_length字节而不是整个字符串做排序。如果只需要排序前面小部分字符,则可以减小max_sort_length的配置,或者使用ORDER BY SUBSTRING(coimn,length).

我们应该避免使用BLOB和TEXT。

使用枚举(ENUM)代替字符串类型

枚举可以把一些不重复的字符串存储为一个预定义的集合。

日期和时间类型

MySQL提供两种相似的日期类型:DATETIME和TIMESTAMP。

DATETIME

这个类型能保存大范围的值,从1001年到9999年,精确到秒。它把日期和时间封装到格式为TTTTMMDDHHMMSS的整数中,与时区无关。使用8个字节的存储空间。
默认情况下,MySQL以一种可排序的,无歧义的格式显示DATETIME 值,例如“2008-01-16 22:37:08”。

TIMESTAMP

TIMESTAMP类型保存了从1970年1月1日午夜以来的秒数,它与UNIX时间戳相同。TIMESTAMP使用4个字节的存储空间,因此它的范围比DATETIME小的多:只能表示1970到2038年MySQL提供了FROM_UNIXTIME()函数把Unix时间戳转换为日期,并提供了UNIX_TIMESTAMP()函数把日期转换为Unix时间戳。

关于日期的存储,除了特殊行为之外,通常应该尽量使用TIMESTAMP,因为它比DATETIME空间效率更高。不建议用整数来保存时间戳的格式,因为处理不方便。

如何存储比秒更小粒度的日期和时间值?
MySQL能存储的粒度到秒,但是可以使用自己的存储格式:可以使用BIGINT类型存储微妙级别的时间戳,或者使用double存储秒后面的的小数部分。

位数据类型

BIT

MySQL会把BIT数据类型当做字符串来处理,如存储一个值为b’0011001的列并且检索它,得到的内容是57的字符串,MySQL将其作为字符串来处理,并且转为相应的数字。因此不建议使用BIT数字类型。
如果想在一个bit的存储空间存储一个true/false值,另一个方法是创建一个可以为空的CHAR(0)列。该列可以保存空值(NULL )或者长度为零的字符串(空字符串)。

一些相关的题目

在表Dept(Dno,Dname,Tele)中,为了尽量减小存储空间,字段Dname存储长度在6-18之间,以下设置的字段类型哪个最合适
A Varchar(10)

B Varchar(20)

C Char(20)

D char(10)
根据上面对VARCHAR和CHAR的总结,我们可以得出答案,使用B。

参考资料

高性能MySQL第三版

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章