postgresql: data type for md5 message digest?
我想使用某个字符串的 MD5 消息摘要作为表的主键。我应该为这样的字段使用什么数据类型?我应该为该字段编写哪些 select 和 insert 语句?
作为 bytea 的 md5 散列将仅使用 16 个字节而不是 32 个字节用于六进制表示:
1 2 3 4
| CREATE TABLE t (d bytea);
INSERT INTO t (d) VALUES
(digest('my_string', 'md5')),
(decode(md5('my_string'), 'hex')); |
以上两种形式都可以使用,但要使用更简单的 digest 功能,需要以超级用户身份安装 pgcrypto 扩展:
1
| CREATE extension pgcrypto; |
如上使用digest函数或decode和md5的组合来搜索某个字符串:
1 2 3 4 5 6 7 8 9 10 11 12 13
| SELECT
octet_length(d) ba_length,
pg_column_size(d) ba_column,
encode(d, 'hex') hex_representation,
octet_length(encode(d, 'hex')) h_length,
pg_column_size(encode(d, 'hex')) h_column
FROM t
WHERE d = digest('my_string', 'md5')
;
ba_length | ba_column | hex_representation | h_length | h_column
-----------+-----------+----------------------------------+----------+----------
16 | 17 | 3d212b21fad7bed63c1fb560c6a5c5d0 | 32 | 36
16 | 17 | 3d212b21fad7bed63c1fb560c6a5c5d0 | 32 | 36 |
pg_column_size 值是存储大小。 bytea 与十六进制表示相比,它不到一半。
bytea 有一个字节的开销,但是填充到八个字节会导致大量的浪费。
相反,考虑使用 uuid 类型,它只使用 16 个字节。选择它时您必须使用类似 REPLACE(md5::text, '-', '') as md5 的东西,但这应该是一个快速操作。
- 你有"填充到 8 个字节"的参考吗?所有文档都说存储大小="1或4字节加上实际的二进制字符串"
-
两个问题:a)您正在存储 1 16=17 个字节,后续列将在 pg_type 中按 typalign 填充,b)请参阅有关 MAXALIGN 的问题和行对齐的页面布局参考。 ["实际的用户数据(行的列)从 t_hoff 指示的偏移量开始,该偏移量必须始终是平台 MAXALIGN 距离的倍数。" == 在 x64 上为 8]。
-
在这种特定情况下,行空间使用量可能为 23 1(最多 8 列的行标题空标题)4(ba_length)4(ba_column)1 16(hex_representation)3(h_length 的对齐填充)4(h_length)4( h_column) = 60 4(行填充)。这就是比使用 uuid 多获得 1 3 4 = 8 个字节的方式。底线:如果您关心空间,则必须关心行布局。通常首先放置大字段接近最佳,但如果它大于 8 个字节,您可能会重新考虑。
-
有趣 - 虽然数字会根据表中下一列的 typalign 值而有所不同,对吧?
-
是的,有可能。一个小的变化可能会产生很大的影响,或者根本没有影响。要考虑的另一件事是,可为空的字段在特定行实例中可能不占用空间,因此,如果您要布置表格以最大程度地节省空间,则需要考虑使用和不使用它们的布局。 (当然,如果多于八列且一列为空,则空位图不再占用 23 字节标头末尾的"空闲"字节,而是由于用户数据对齐而将行大小增加了 MAXALIGN -添加列时可能会导致表大小显着且令人困惑的增加。)
-
如果您愿意滥用 Null,则可以节省大量资金。在一个案例中,我通过使用 coalesce() 在 1200 万行表中的 70% 行上节省了 8 个字节,以允许存储空值来替代最流行的值。显然,这只是在您实现显着节省并完全控制应用程序时才需要考虑的事情。
-
谢谢 我很高兴被介绍给我以前从未考虑过的这些问题。您可能会发现 DBA.SE 上的一些问题很有趣,例如这个旧问题。