对比char和varchar随便在google或百度中搜一下得到的结论大概都是"char定长,varchar不定长,char要比varchar占用更多的空间,由于定长char的效率高于varchar,char最大255,varchar最大65536"更高级一点的数据是"char在存入和取出的时候,会自动把末尾的空格去掉,varchar会额外的多用1-2个字节来存放字符长度,列中有一个varchar会自动把char转换成varchar,而当varchar长度小于4时,自动的把varchar转换成char..." 一般认为空间换时间,现在磁盘又大又不值钱! 当使用全表都是char这的字段的时候,那么表属性Row_format是Fixed也就是静态表,与之对应的自然就是动态表Dynamic,静态表比动态表效率要高,主要是因为,基于两点: 1)没有碎片,每行的长度是固定,所以在频繁更新的场景下,尤其是某个字段由小变大. 2)方便数据文件指针的操作,在myisam中有一个数据文件指针的概念,是用来指向数据文件,比如在索引中指向数据文件.静态表的偏移量的固定不变的,而在动态表中每行的数据长度大小不一,就可能导致数据更多的开销 基于以上两点,所以静态表在查询,修改拥有较大优势,但是这个优势也是有适用场景的. 首先猜想char由于每次存取都会自动的削掉末尾的空格,而且数据文件也大,所以会使用更多的cpu和内存资源,尤其在取的时候,要是长短差距较大的时候,还是会很浪费操作的. 其次验证想法,首先测试插入性能,建了2张表并调用sp分别插入200W的数据 CREATE TABLE `isam_char` ( `content` char(255) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8; CREATE TABLE `isam_vc` ( `content` varchar(255) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8; call insert_isam(2000000,'isam_char'); call insert_isam(2000000,'isam_vc'); 多次平均isam_char插入200W的数据为138.21s,而isam_vc少了约20s为119.80s,这应该是每次插入的时候,mysql要把char字段填充到255的操作.观察数据文件大小,isam_vc为235.8M而isam_char为1.4G! 再测试查询,为了保证两者一致,首先把isam_char中数据删除,再把isam_vc中数据导入isam_char中,无索引,禁闭query_cache truncate table isam_char;##观察了下数据文件,被穷空成0 insert into isam_char select * from isam_vc;##观察了下数据文件,依然是1.4G select * from isam_char limit 1555555,5; select * from isam_vc limit 1555555,5; 依旧多次查询去平均值,isam_char表平均值为10.50s,而isam_vc则为1.51s! 再看下创建索引,以及索引的使用情况 mysql> create index index_char on isam_char(content); Query OK, 2000001 rows affected (2 min 56.33 sec) Records: 2000001 Duplicates: 0 Warnings: 0 mysql> create index index_vc on isam_vc(content); Query OK, 2000001 rows affected (1 min 31.98 sec) Records: 2000001 Duplicates: 0 Warnings: 0 mysql> select count(*) from isam_char where content=('iamauperman!iwillbeahero!!'); +----------+ | count(*) | +----------+ | 199669 | +----------+ 1 row in set (0.56 sec) mysql> select count(*) from isam_vc where content=('iamauperman!iwillbeahero!!'); +----------+ | count(*) | +----------+ | 199669 | +----------+ 1 row in set (0.31 sec) 还是不理想,所以在长度很不固定情况下使用char或静态表是很不理想的事,当然这里做的是全索引扫描,动态表的索引要小于动态表,估计最大的优势是使用索引去找数据和update,为了验证,再次测试update. mysql> update isam_char set content='iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!'; Query OK, 2000001 rows affected (54 min 54.25 sec) Rows matched: 2000001 Changed: 2000001 Warnings: 0 mysql> update isam_vc set content='iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!iwillbeahero!!iamauperman!'; Query OK, 2000001 rows affected (1 hour 59 min 25.73 sec) Rows matched: 2000001 Changed: 2000001 Warnings: 0 果然啊,更新200W的数据差了1倍多!同时动态表的数据增大为480.7M.顺便读了几次数据,依然有差距 mysql> select count(*) from isam_vc IGNORE INDEX(index_vc) where content='iamauperman!iwillbeahero! !'; +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (10.55 sec) mysql> select count(*) from isam_char IGNORE INDEX(index_char) where content='iamauperman!iwillbeah ero!!'; +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (14.98 sec) 不使用索引,做全表扫描,动态表快于静态表,这可能是数据文件大小的差异吧. 由于数据源和时间的问题,今天就不做扫描完索引再去读数据的实验了. 基本得出结论:mysql里,准确的说是myisam引擎中,静态表又或者char的长处在于更新操作,读取(不使用索引读取)和插入相比varchar又或动态表,并无优势. 本测试环境为winXP+mysql-5.1.44-community,配置为mysql默认配置.无修改. 注:做这个测试说明我好奇心很强,还有就是我真的很无聊,假如你看了,觉得错了,有明显漏洞的地方,欢迎指正!你也别骂我,我知道我是菜鸟,mysql程序不是有个选项叫做—i-am-a-dummy吗,我就是一个dummy,呵呵,浪费你的时候,我知道我错了! 附:插数据的sp CREATE DEFINER=`root`@`localhost` PROCEDURE `insert_isam`(p int,t char(10)) begin set @i = 0; set @str = "iamauperman!iwillbeahero!!"; repeat #select name into @str from mysql.help_topic order by rand() limit 1; set @str=substr(@str,1,25); set @ins_str = repeat(@str,floor(rand()*10)); set @cmd=concat('insert into ',t,' (content) values("',@ins_str,'")'); prepare stmt from @cmd; execute stmt; set @i = @i+1; until @i > p end repeat; end |
|