我有一个存储MD5哈希的索引列。因此,该列将始终存储32个字符的值。无论出于何种原因,它都是作为varchar而不是char创建的。迁移数据库以将其转换为char值得麻烦吗?这是在带有InnoDB的MySQL 5.0中。
我有一个存储MD5哈希的索引列。因此,该列将始终存储32个字符的值。无论出于何种原因,它都是作为varchar而不是char创建的。迁移数据库以将其转换为char值得麻烦吗?这是在带有InnoDB的MySQL 5.0中。
Answers:
之前有人问过类似的问题
这是我答案的摘录
您必须意识到使用CHAR与VARCHAR的权衡
使用CHAR字段,您分配的正是您所获得的。例如,无论您在字段中放置的字符如何,CHAR(15)都会分配并存储15个字节。字符串操作简单明了,因为数据字段的大小是完全可以预测的。
使用VARCHAR字段,您将获得完全不同的故事。例如,VARCHAR(15)实际上动态分配最多16个字节,最多动态分配15个数据,并至少分配1个额外的字节来存储数据的长度。如果您要存储的字符串'hello'将占用6个字节,而不是5个字节。在所有情况下,字符串操作都必须始终执行某种形式的长度检查。
当您做两件事时,这种折衷会更加明显:1.存储数百万或数十亿的行2.索引为CHAR或VARCHAR的列
TRADEOFF#1显然,VARCHAR占有优势,因为可变长度数据将产生较小的行,从而产生较小的物理文件。
TRADEOFF#2由于CHAR字段由于固定的字段宽度而需要较少的字符串操作,因此针对CHAR字段的索引查找平均比VARCHAR字段快20%。我这不是任何猜想。《 MySQL数据库设计和调优》这本书在MyISAM表上做了出色的工作来证明这一点。本书中的示例执行了以下操作:
ALTER TABLE tblname ROW_FORMAT=FIXED;
该指令强制所有VARCHAR充当CHAR。我在2007年的上一份工作中做到了这一点,并使用了300GB的表,并将索引查找速度提高了20%,而没有进行任何其他更改。它像出版一样工作。但是,它的确产生了几乎两倍大的表,但这只是权衡第一。
您可以分析所存储的数据,以查看MySQL对列定义的建议。只需对任何表运行以下命令:
SELECT * FROM tblname PROCEDURE ANALYSE();
这将遍历整个表,并根据其包含的数据,最小字段值,最大字段值等为每列推荐字段定义。有时,您只需要在规划CHAR与VARCHAR时使用常识。这是一个很好的例子:
如果要存储IP地址,则该列的掩码最多为15个字符(xxx.xxx.xxx.xxx)。我会CHAR(15)
心跳一跳,因为IP地址的长度不会有太大变化,而且字符串处理的复杂性由一个额外的字节控制。您仍然可以PROCEDURE ANALYSE()
针对这样的列执行操作。它甚至可能建议使用VARCHAR。在这种情况下,我的钱仍将超过VARCHAR放在CHAR上。
CHAR与VARCHAR问题只有通过适当的计划才能解决。强大的力量伴随着巨大的责任(陈词滥调,但事实如此)。
更新
说到MD5,strlen
在切换整个行格式时,应消除内部计算。无需更改字段定义。
如果MD5键是唯一存在的VARCHAR,我将使用它并将表行格式转换为fixed。如果存在大量其他VARCHAR字段,它们也将受益。作为交换,桌子将扩展到其大小的两倍左右。但是,在不进行其他调整的情况下,查询应该可以加快20%的速度。
bit
和binary
?
看来您将每个值转换为可以节省1个字节或大约3%char
。如果您仍然以十六进制存储MD5,则可能不值得-通过使用a可以节省50%binary
。
感谢Ovais(请参阅注释)指出,如果使用多字节字符集,则char(32)
可以使用32个以上的字节。
感谢Rick James指出您应该使用unhex
函数将十六进制字符串转换为二进制:
create table foo(bar varbinary(100)); insert into foo(bar) values(md5('a')); insert into foo(bar) values(unhex(md5('a')));
select length(bar) from foo;
| 长度(巴)| | ----------:| | 32 | | 16 |
db <> 在这里拨弄
binary
-还是我误解了?
BINARY
除非也使用,否则更改为几乎没有作用UNHEX()
。也就是说,你可以储存UNHEX(MD5(x))
到一个16字节的BINARY(16)
过度节省存储空间显著MD5(x)
成CHAR(32) CHARACTER SET ascii
。
我认为这不值得改变。如果您浏览此处的文档,则应说明两者之间的区别。在您的使用场景中,除非您真的担心与行大小相关的额外开销,否则一个并不会真正提供任何明显的好处。
http://dev.mysql.com/doc/refman/5.0/en/char.html
还要注意上面我链接到的文档的第一条评论...“只有在整个记录都是固定大小的情况下,CHAR才会加快访问速度。也就是说,如果使用任何可变大小的对象,都可以将它们全部制成可变大小。通过在还包含VARCHAR的表中使用CHAR,您不会获得任何速度”