1、当一个列可以选择多种数据类型时,应该优先考虑数字类型,其次是日期和二进制类型,最后是字符类型。
2、对于相同级别的数据类型,应该优先选择占用空间小的数据类型。
1、首先在对数据进行比较,比如查询条件、关联排序时,字符处理,与当前所使用的排序规则是相关的,而数字与二进制则不需要参照字典的排序规则,其处理是按照二级制的大小来进行的,同样的数据,字符串处理往往要比数字慢;
2、另外在数据库中,数据处理是以页为单位的,每个页能存储的数据量是一定的,在INNODB中是16K,列的长度越小,就意味着列能够在页中容纳的数据行就越多,这样在加载同样的数据时,使用宽度较小的类型,要比使用宽度较大的类型所要加载的数据页就少,从而也减少了磁盘IO,有利于性能的提升。
如,DECIMAL(18, 9)就需要9个字节来存储。前面九个数字,占4个字节,后面九个数字,占4个字节,小数点占1个字节,总共,9个字节。
MySQL5.0 版本之后,DECIMAL最多允许存储65个数字,这对于我们实际操作,已经完全足够了。如果我们的业务涉及到财务,就得使用DECIMAL这种精确数字的类型。而对于其他的情况,就可以使用DOUBLE和FLOAT这些类型。
VARCHAR长度的选择问题
1、使用最小符合需求的长度。
这个要做到,不容易,首先,我们很难确定,什么是最小的符合需求的长度,这个要根据业务来定,比如用户姓名这一列,如果只存中文名,长度应该不会超过10个字符,因为,很少几乎就没有中国人的姓名有10个字,但是,如果还要存储外国人的姓名,那么,宽度可能要增加到20个宽度的字符了,外国人的姓名通常是很长的。但是,无论如何也不应该使用VARCHAR 255 来定义列的长度,因为也没有人会有这么长的名字。
另外,还有一个点要注意,虽然我们希望VARCHAR类的长度尽可能的小,但是,我们也不能不顾业务的情况,而去故意设小,并想着,以后长度不够了,再改呗,如果这么想,那就大错特错了,因为业务一旦上线,再进行列的宽度的修改的话,那样做的成本是非常大的,在MySQL5.7之前的版本中,对于VARCHAR类的宽度,无论是改大还是改小,都是要锁表的。就算是在MySQL5.7版本之后,也只是说,如果VARCHAR列的宽度是在255个字节以内,改变后的宽度同样不超过255个字符,这样,是可以不锁表的。
注意,在生产环境中,如果发生锁表,在一个繁忙的系统中,肯定会发生很严重的系统性能问题。
2、VARCHAR(5)和VARCHA(255) 存储”MySQL”字符串性能的不同。
这两个长度都是没有超过255的,所以,都需要占用1个额外的存储字节,来存储字符串的长度,因此,存储MySQL这个字符串,只需要6个字节,就够了,那么,我们还有必要选择最小的列的宽度么?不是不超过255个长度,存储都是一样的么?其实,答案是,我们还是需要选择最小的列的宽度的,这是因为,MySQL为了能够更有效地优化查询,所以在内存中,对于字符串使用的是固定的宽度,特别是在使用一些隐式的内存临时表的时候,更是这样,所以,如果我们把列的宽度定义的太长,就会消耗更多的内存,所以,这才是我们要求对MySQL的列的宽度来选择最小的符合需求的长度的原因。
VARCHAR的适用场景
1、适合字符串列的最大长度比平均长度大很多的字符串。这种情况,更能发挥出VARCHAR列变长存储的特点。
2、适合字符串很少被更新的列。
3、适合使用多字节字符集存储字符串的列,比如UTF8,因为这样的字符集,可能使用不同的字节数进行存储,以UTF8为例,如果我们存储中文,可能需要3个字节,而如果存储英文和数字,则只需要一个字节。
CHAR类型的存储特点
1、CHAR类型是定长的。MySQL总是根据定义的CHAR类型的宽度,来分配足够的空间,存储CHAR类型中的数据。也就是说,如果我们定义的CHAR类型的宽度是50,如果只存储了10个字符,那么在存储时,也会分配50个字符的存储空间。
2、CHAR类型中存储的字符串的末尾如果存在空格,那么末尾的空格将会被删除。同样的,VARCHAR中,就不会删除末尾的空格。
3、CHAR类型的最大宽度只有255,如果超过这个宽度,则要使用VARCHAR类型。
CHAR类型中的存储场景
1、CHAR类型适合存储长度近似的值的长度。因为CHAR类型是定长的,如果长度接近某个值的,则可以给其一个固定的长度。这样就不会浪费存储空间和内存,这类字符串,有一个很好的例子,那就是MD5值,加密存储32位定长长度的字符,这种情况,就非常适合,另外,身份证,手机号,也很适合CHAR类型字段的存储。
2、CHAR类型适合存储短字符串。短的字符串,存储在CHAR类型中,比存储在VARCHAR类型中,更节省空间。比如我们有一个列,用来存储用户的性别,男或女,使用CHAR(1)比使用VARCHAR(1)更适合,同样,以UTF8为例,在CHAR类型存储,只需要3个字节,而VARCHAR(1)因为还需要一个额外的字节来存储变长字符串的长度,所以,使用VARCHAR就需要4个字节,所以,从这种情况来看,短字符,使用CHAR比VARCHAR更有效率。
3、CHAR类型适合存储经常更新的数据的列。因为CHAR类型的长度是固定的,MySQL会一次性地存储足够的空间,所以,在多次更新时也不会产生页分裂的情况,也可以避免产生存储碎片,获取更好的IO性能。
DATETIME类型
以YYYY-MM-DD HH:MM:SS[.fraction] 格式存储日期时间。默认情况,是以 年月日时分秒的格式来存储时间的,即datetime = YYYY-MM-DD HH:MM:SS。在MySQL5.6之前,能够存储的最小的精度是秒,而在MySQL5.6之后,可以存储到微秒。
如果我们想保存微秒,就要为DATETIME定义一个宽度,宽度的最大值是6, 如:
datetime(6) = YYYY-MM-DD HH:MM:SS.fraction
DATETIME是与时区无关的,占8个字节的存储空间。还有一点需要注意,那就是,DATETIME的存储范围 1000-01-01 00:00:00 到 9999-12-31 23:59:59。通常情况下,我们都可以使用DATETIME来存储时间。
TIMESTAMP类型
它是一种非常有特色的日期时间类型,从名字来看,我们就能知道,这种类型存储的是时间戳,也就是格林尼治时间1970年1月1日到当前时间的秒数。这和我们所熟悉的UNIX时间戳,是一样的。
默认是以YYYY-MM-DD HH:MM:SS.[.fraction]格式显示,占用4个字节。由此,我们可以看出,TIMESTAMP类型要比DATETIME类型小的多,更加节约空间。
时间范围:1970-01-01 到 2038-01-19
TIMESTAMP类型显示依赖于所指定的时区。在不同的时区下,显示不同的值,如果我们是在多个时区使用这个类型,就需要注意。
另外,在当前行的数据,修改时,可以自动修改TIMESTAMP列的值。这个功能,非常有用,我们经常用这个功能标明每行数据的最好修改时间。
DATE和TIME类型
在MySQL5.6,又增加了DATE和TIME两种时间类型,在保存时间数据时,我们经常会有这样的需求,比如存储生日,那么,就只需要存储日期,而不用存储时间,这种情况,在MySQL5.6之前,我们通常这么实现:
1、把日期部分存储为字符串(至少要8个字节)
2、使用INT来存储(4个字节)
3、使用DATETIME类型来存储(需要8个字节)
DATE类型的优点:
1、占用的字节数比使用字符串、DATETIME、INT存储要少,使用DATE类型,只需要3个字节。
2、使用DATE类型,还可以利用日期时间函数进行日期之间的计算。这是INT类型、字符串类型存储日期所做不到的。
3、DATE的时间范围是 1000-01-01 到 9999-12-31.
TIME类型
主要用于存储时间数据,格式为HH:MM:SS,同时,也可以指定宽度来保存微秒的数据。
1、不要使用字符串类型来存储日期时间数据。在实际的开发过程中,很多开发人员喜欢使用字符串来存储日期时间数据,这样,是不合适的,因为日期时间类型通常比字符串占用的存储空间小。其次,日期时间类型在进行查找过滤时,可以利用日期来进行对比,如果我们使用字符串,那么就只能按照字符集来顺序进行过滤了。还有,日期时间类型还有着丰富的处理函数,可以方便的对日期类型来进行日期计算。
2、使用INT存储日期时间不如使用TIMESTAMP类型。如果要存储UNIX时间戳的话,用INT还不如直接使用TIMESTAMP类型,因为这个类型本身就是以INT类型来存储的,只不过显示的是以年月日时分秒的格式显示的,所以,在使用时更加方便,不用每次使用都用函数来进行转换,就可以很直观地看出时间。