用于存储MD5哈希或NULL的最佳MySQL数据类型是什么?

14

我有一个PHP应用程序,将所有账户存储在同一个表中,无论它们是否处于活动状态。该表有一列名为"active",其值可以是NULL(表示账户处于活动状态),或包含MD5哈希值(表示账户不活动)。

根据在MySQL中高效存储MD5哈希的最佳实践,如果该列始终包含MD5哈希而从不为NULL,则BINARY(16)是首选,CHAR(32)是次佳选择。由于我的大多数账户都处于活动状态,因此大多数列值将为NULL,那么我是否更好地使用不同的数据类型,例如VARCHAR(32)?


2
可以的,VARCHAR(32) 更好。 - Sumit Bijvani
3个回答

29

使用 VARCHAR 没有意义。MD5 哈希值始终为 128 位,因此 CHAR(32) 保存十六进制数字的字符串,或者 BINARY(16) 保存解码十六进制数字后的字节字符串。

使用 NULL 与数据类型选择无关。MySQL 可以在需要字符串(CHAR 或 VARCHAR)时存储 NULL。但是实际上,在 InnoDB 默认的行格式中,MySQL 不会存储任何 NULL,对于列为空的情况,不会存储任何内容。


参考文献:http://dev.mysql.com/doc/internals/en/innodb-field-contents.html

  • 关于 NULL 的一些注意事项:

    对于第三行,我在 FIELD2 和 FIELD3 中插入了 NULL。因此,在“字段起始偏移量”中,这些字段的最高位为 1(值为 94 十六进制),而不是 0(值为 14 十六进制)。由于 NULL 不占用空间,所以该行更短。

(强调是本人添加)


感谢您的回答,Bill。根据您的解释,如果我使用CHAR(32)或BINARY(16),并且存储的值为NULL,那么我的开销不会比使用VARCHAR(32)更大。非常感谢,希望您是正确的! - user1032531
1
+1 Bill 和 @user1032531 Bill 意味着你应该使用 CHAR(32) 或 BINARY(16)。当你使用 VARCHAR 时,开销会更大,因为 MySQL 需要额外保存两个 shorts 来知道你的 VARCHAR 多大。当你定义 ascii_bin 字符集时,在理论上,精确查找键应该在 CHAR 列上更快。 - Raymond Nijland

3

注:更新日期:2019年5月11日

理想情况下,您不应再使用MD5来哈希密码。 PHP手册已经添加了一个安全的密码哈希部分,大约在4-5年前,其中解释了password_hash()password_verify()以及为什么不适合使用MD5 / SHA1..

请记住,由于大多数关系型数据库管理系统(RDMS)都设计成可以提供非常稳定的时间,因此当password列在WHERE子句中时,大多数RDMS会缓存数据在内存中或索引化数据,这使得定时攻击变得非常可能。

在“伪”PHP代码中,结合SQL使用password_verify()的安全方法是完全可行的。

$row = prepare("SELECT password FROM users WHERE username = :username").execute().fetch(); 
if (password_verify($_POST['password'], $row->password)) { 
  // password correct
} else {
  // password incorrect..
}

在MySQL源代码的strings/ctype-bin.c文件中定义了BINARY类型。这看起来像是将默认的C ascii字符集转换为二进制形式。理论上,这应该比使用带有ascii_bin字符集的CHAR(32)更快。
因为写入/读取二进制所需的时间更少,在索引和内存中占用的磁盘空间也更少,而CHAR(32)数据类型比BINARY类型多16个字节。
如果您想使用它,请使用此php代码。
<?php
  md5 ( "password", true ); // true returns the binary what is 16 bytes long  MySQl BINARY(16)
?>

-12
你可以使用php函数md5()。它更有效率,而且如果有人在你发送到数据库的时候拦截了数据,那么这些数据已经被加密了。

5
这如何回答问题? - mistika

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接