数据类型的选择
如果需要学习数据库设计方面的基础知识,建议阅读Clare Churcher的Beginning Database Design。
不管存储哪种类型的数据,下面几个简单的原则都有助于做出更好的选择。
更小的通常更好
更小的数据类型通常更快,因为它们占用更少的磁盘、内存和CPU缓存,并且处理时需要的CPU周期也更少。
如果无法确定哪个数据类型是最好的,就选择你认为不会超过范围的最小类型。
简单就好
应该使用MySQL内建的类型而不是字符串来存储日期和时间,另外一个是应该用整型存储IP地址。
尽量避免NULL
通常情况下最好指定列为NOT NULL ,除非真的需要存储NULL 值。
如果查询中包含可为NULL 的列,对MySQL来说更难优化,因为可为NULL 的列使得索引、索引统计和值比较都更复杂。
各数据类型注意事项
因为需要额外的空间和计算开销,所以应该尽量只在对小数进行精确计算时才使用DECIMAL ——例如存储财务数据。
但在数据量比较大的时候,可以考虑使用BIGINT 代替DECIMAL ,将需要存储的货币单位根据
小数的位数乘以相应的倍数即可。假设要存储财务数据精确到万分之一分,则可以把所有金额乘以一百万,然后将结果存储在BIGINT 里,这样可以同时避免浮点存储计算不精确和DECIMAL 精确计算代价高的问题。
VARCHAR 节省了存储空间,所以对性能也有帮助。但是,由于行是变长的,在UPDATE 时可能使行变得比原来更长,这就导致需要做额外的工作。
下面这些情况下使用VARCHAR 是合适的:字符串列的最大长度比平均长度大很多;列的更新很少,所以碎片不是问题;使用了像UTF-8这样复杂的字符集,每个字符都使用不同的字节数进行存储。
在5.0或者更高版本,MySQL在存储和检索时会保留VARCHAR类型数据的末尾空格。但在4.1或更老的版本,MySQL会剔除末尾空格。
当存储CHAR 值时,MySQL会删除所有的末尾空格。
CHAR 适合存储很短的字符串,或者所有值都接近同一个长度。对于经常变更的数据,CHAR 也比VARCHAR 更好,因为定长的CHAR 类型不容易产生碎片。
BLOB 和TEXT 都是为存储很大的数据而设计的字符串数据类型,分别采用二进制和字符方式存储。MySQL把每个BLOB 和TEXT 值当作一个独立的对象处理。
MySQL能存储的最小时间粒度为秒。
MySQL提供两种相似的日期类型:DATETIME 和TIMESTAMP
DATETIME
从1001年到9999年,精度为秒。它把日期和时间封装到格式为YYYYMMDDHHMMSS的整数中,与时区无关。使用8个字节的存储空间。
TIMESTAMP
TIMETAMP 类型保存了从1970年1月1日午夜(格林尼治标准时间)以来的秒数,它和UNIX时间戳相同。TIMESTAMP 只使用4个字节的存储空间。只能表示从1970年到2038年。
如果在多个时区存储或访问数据,TIMESTAMP 和DATETIME 的行为将很不一样。前者提供的值与时区有关系,后者则保留文本表示的日期和时间。
除了特殊行为之外,通常也应该尽量使用TIMESTAMP ,因为它比DATETIME 空间效率更高。
可以使用BIGINT 类型存储微秒级别的时间截,或者使用DOUBLE 存储秒之后的小数部分。
MySQL把BIT 当作字符串类型,而不是数字类型。当检索BIT(1) 的值时,结果是一个包含二进制0或1值的字符串,而不是ASCII码的“0”或“1”。在数字上下文的场景中检索时,结果将是位字符串转换成的数字。
应该谨慎使用BIT类型。
如果可能,应该避免使用字符串类型作为标识列(ID),因为它们很消耗空间,并且通常比数字类型慢。
如果存储UUID值,则应该移除“-”符号;或者更好的做法是,用UNHEX() 函数转换UUID值为16字节的数字,并且存储在一个BINARY(16) 列中。检索时可以通过HEX() 函数来格式化为十六进制格式。
应该用无符号整数存储IP地址。MySQL提供INET_ATON() 和INET_NTOA() 函数在这两种表示方法之间转换。