mysql几个经典数据类型选择

mysql中,对数据类型的合理选择,有利于我们在检索时,更快的获取数据,或者更精确的进行计算。

选择char还是varchar

首先,这两个类型都表示字符串类型,我们都知道char存储需求是固定的,例如char(16)就会产生16字节,即使值是空的,而varchar的存储需求是变动的,根据存入的值的多少进行变化,例如varchar(16),虽然你保存了'abc',但它并不会消耗16个字节,而是4个字节。同时你要注意,如果存入的字符串长度超过16个字符,则会报错,即使强行存入,也仅保留了前面16个字符。

其次,什么情况下会影响查询性能?我们在阅读一些文章时,总是指出固定的长度检索速度更快。但其实这是在一定条件下。当使用MyISAM引擎时,char会比varchar更快,因为char(16)的字段中如果保存'abc',存储时实际存储的是'abc             ',系统不会以16个字节去进行检索,而是将末尾的空格去掉,实际上直接获取了'abc'检索对比,而如果varchar(16)中保存了'abc',虽然不会在实际存储中添加空格,但是数据库会给这个字段增加一个长度,因此,varchar的实际容量会大1-2字节,在检索时,需要先获取这个长度,然后在对值进行对比,因此速度反而更慢。所以,如果使用MyISAM引起,char的性能会好一些。但是在使用InnoDB引擎时,情况就不一样了,存储方面仍然是按照上述方法进行存储,但是在查询时,InnoDB引擎直不再区分数据存储长度,而是直接通过数据在存储器上的指针找到数据,因此实际上上述的影响全部不存在了。但是数据的读取受到磁盘I/O的影响,如果一个字符串存储所占的存储空间更大,那么读取时也就更耗时,如果数据量很大,那么char那些空出来的多余存储空间实际上就拖慢了读取速度。不过有一个情况还是char更快,就是char(16)和varchar(16)所有记录都存满了16个字符,这个时候因为varchar多存了字符长度,反而在存储空间上又失去了优势,所以,如果你知道某个值一定是多少位,例如md5散列,一定是32位,那么可以考虑char(32)。

网上还有一些说法,比如:MEMORY数据表目前都使用固定长度的数据行存储,因此无论使用CHAR或VARCHAR列都没有关系。两者都是作为CHAR类型处理的。

在使用text和blob数据类型时如何提高查询性能

虽然这里只提到了text和blob,但是实际上这里可以扩展到所有字符串长度超过你认为比较大的一个值的时候的类型。比如varchar(255)等,text和blog也各自包含四种类型。我们不可能用text类型直接去查询对比吧,因此,建议在需要利用text进行对比时,额外建一个字段,用于保存这个text的散列值,可以是MD5(),SHA1()或CRC32(),在检查某个值是否存在时,先通过程序端处理出散列值,再到数据库中去匹配,看看对应的值是否存在。如果这些值经常用于检索,你甚至可以给这个散列值字段建立索引。

如果你采用这种方法,还需要注意两件事,第一件,散列值如果能通过算法生成数值型数据,就以数值型保存,因为我们都知道,检索数值型比检索字符串快的多,而且,如果使用字符串类型,进行><=这类查询是没有意义的,因为这种比较查询会严重拖慢查询速度;第二件,在查询时,select时尽可能的过滤查询text或blob字段,例如select * 这样的查询语句尽可能不用,因为这样用,即使你按照上述方法建立了一个查询,但是在数据库从磁盘读取数据库过程中,仍然需要去把text或blob取出来,和你直接按老办法进行检索效果是一样的。

还有一个不是很容易让人忽略的事,就是text和blob在执行UPDATE时,可能会出现很多冗余,导致数据库占用比较多的空间,因此,我们需要偶尔使用OPTIMIZE TABLE优化清除冗余空间。不过,其实我们可以想一下另外的办法,其中最好的办法就是将原有记录删除,再新增一条记录。但是这可能会引起主键的变化,因此我们可以采用一种更偏门的办法,将text和blob字段放到一个新表中,这个表中仅记录对应的id,散列值和真正的文档值,而在原表中记录散列值,这样,当更新(仅更新)文档时,直接使用REPLACE INTO,根据id,进行更新(插入),因为replace into更新数据时,会删除原始记录,创建新记录,所以实际上就会清空原来的存储单位,从而实现节省空间的目的。(这仅是一种思路,未经验证~)

浮点数与定点数:float、double、decimal

浮点数,顾名思义,是浮动的,变动的,其值会在程序运行中出现轻微的偏差,例如一个数加上另一个数,再减去同一个数时,可能得到的不是原数(虽然很接近)。而定点数就不存在这个问题。float、double、decimal三种数据类型中,float、double是浮点数,decimal是定点数。

在使用中,如果追求精度,必须使用decimal,否则经过多次运算,很有可能导致数据最后很不准确。

2015-08-13