教学之友,学习之友。

站长教学网

当前位置: 站长教学网 > 数据库 > MYSQL教程 >

MySQL的varchar和char查询效率测试

时间:2013-01-21 12:26来源:未知 作者:ken 点击:

对比char和varchar随便在google或百度中搜一下得到的结论大概都是"char定长,varchar不定长,char要比 varchar占用更多的空间,由于定长char的效率高于varchar,char最大255,varchar最大65536"更高级一点的数据是"char在存入和取出的时候,会自动把末尾的空格去掉,varchar会额外的多用1-2个字节来存放字符长度,列中有一个varchar会自动把 char转换成varchar,而当varchar长度小于4时,自动的把varchar转换成char..."

一般认为空间换时间,现在磁盘又大又不值钱! 站长教学网 eduyo.com

当使用全表都是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

(责任编辑:ken)
TAG标签: mysql 索引 效率
顶一下
(2)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
注册登录:不允许匿名留言,登录后留言无需输入验证码。
栏目列表
最新内容