Jas*_*ker 66 mysql innodb performance varchar
我有一个存储 MD5 哈希的索引列。因此,该列将始终存储 32 个字符的值。无论出于何种原因,它都是作为 varchar 而不是 char 创建的。迁移数据库以将其转换为字符是否值得?这是在带有 InnoDB 的 MySQL 5.0 中。
Rol*_*DBA 63
之前有人问过类似的问题
这是我的回答的摘录
您必须意识到使用 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 Database Design and Tuning》一书在 MyISAM 表上做了一些奇妙的事情来证明这一点。书中的例子做了如下的事情:
ALTER TABLE tblname ROW_FORMAT=FIXED;
Run Code Online (Sandbox Code Playgroud)
该指令强制所有 VARCHAR 都表现为 CHAR。我在 2007 年的上一份工作中做到了这一点,并使用了一个 300GB 的表并将索引查找速度提高了 20%,而没有更改任何其他内容。它按发布的方式工作。然而,它确实产生了一张几乎两倍大小的表,但这只是回到权衡#1。
您可以分析存储的数据以查看 MySQL 推荐的列定义。只需对任何表运行以下命令:
SELECT * FROM tblname PROCEDURE ANALYSE();
Run Code Online (Sandbox Code Playgroud)
这将遍历整个表并根据它包含的数据、最小字段值、最大字段值等为每一列推荐列定义。有时,您只需要使用常识来规划 CHAR 与 VARCHAR。这是一个很好的例子:
如果要存储 IP 地址,则此类列的掩码最多为 15 个字符 (xxx.xxx.xxx.xxx)。我会立刻跳起来,CHAR(15)因为 IP 地址的长度不会有太大变化,而且字符串操作的复杂性由一个额外的字节控制。你仍然可以PROCEDURE ANALYSE()对这样的专栏做一个。它甚至可能会推荐 VARCHAR。在这种情况下,我的钱仍然会放在 CHAR 上而不是 VARCHAR 上。
CHAR 与 VARCHAR 问题只能通过适当的计划来解决。强大的力量伴随着巨大的责任(陈词滥调,但确实如此)。
更新
对于MD5,strlen在切换整个行格式时,内部的计算应该被取消。无需更改字段定义。
如果 MD5 键是唯一存在的 VARCHAR,我会选择它并将表行格式转换为 fixed。如果存在大量其他 VARCHAR 字段,它们也会受益。作为交换,桌子会扩大到原来的两倍。但是查询速度应该会提高大约 20%,而无需额外调整。
Jac*_*las 20
它看起来像你会节省每值1个字节或约3%的转换为char。如果您无论如何都以十六进制存储MD5,则可能不值得- 您可以通过使用 abinary来节省 50% 。
感谢 Ovais(见评论)指出如果您使用多字节字符集,它char(32)可以使用超过 32 个字节。
感谢 Rick James 指出您应该使用该unhex函数将十六进制字符串转换为二进制:
Run Code Online (Sandbox Code Playgroud)create table foo(bar varbinary(100)); insert into foo(bar) values(md5('a')); insert into foo(bar) values(unhex(md5('a')));
Run Code Online (Sandbox Code Playgroud)select length(bar) from foo;| 长度(条)| | ----------: | | 32 | | 16 |
db<>在这里摆弄
RTh*_*mas 15
在我看来,这不值得改变。如果您查看此处的文档,它应该说明两者之间的区别。在您的使用场景中,除非您真的担心与行大小相关的额外开销,否则一个并没有真正提供任何显着的好处。
http://dev.mysql.com/doc/refman/5.0/en/char.html
还要注意我上面链接到的文档的第一条评论...“如果整个记录是固定大小,CHAR 只会加快您的访问速度。也就是说,如果您使用任何可变大小的对象,您不妨将它们全部可变大小。在还包含 VARCHAR 的表中使用 CHAR 不会提高速度”
| 归档时间: |
|
| 查看次数: |
75933 次 |
| 最近记录: |