我有一个网站项目,我必须在 postgres 表中处理数千或数万个对象。
最初我的网址是:
example.com/object/{ID}/{TEXT SLUG}/
其中 {ID} 只是一个与我的表中的串行主键相对应的整数,{TEXT SLUG} 除了出于 SEO 友好的原因之外实际上什么都不做。
现在,我想隐藏我的 {ID},因为有人可能只是使用一些简单的脚本请求所有增加 {ID} 的对象并简单地重建我的数据库,我想将 url 设计得更现代
example.com/object/{TEXT SLUG}/
现在,如果我直接使用 {TEXT SLUG} 寻址表,它不会比以前使用 {ID} 简单寻址慢得多,即使使用一些索引,尤其是当它变大时(我希望在 40K 范围内最多 60K 行,但表中目前只有 2K)?
我想使用一些轻量级的散列算法来散列 {TEXT SLUG} 并使用散列对表进行寻址,并添加一个具有散列副本的附加列。由于 Postgres 有 4 或 8 字节整数,我很想使用一些轻量级的 128 位散列算法(例如 Murmurhash),我是否正在考虑使用散列 slug 的想法,还是有什么我不知道的?
按照今天的标准,60K 行确实很小,并且通过整数主键和索引文本块查找之间的差异在实践中可能并不明显。
话虽如此,如果您无论如何都必须压缩性能,那么您正在考虑的更改仍有改进的空间。
首先,实际上不需要为散列值添加列,因为 PostgreSQL 可以直接索引函数结果:
其次,甚至不需要将散列存储在附加索引中。相反,可以使用保留格式的加密方案通过 slug 以无法猜测的形式导出您的 ID。与哈希相比,这种技术有几个优点:
无存储:ID 到 slug 和 slug 到 ID 的转换由 O(1) 复杂度的不可变函数完成。
哈希在理论上不是唯一的,而加密具有唯一性的数学保证。请参阅哪种散列算法最适合唯一性和速度?对常见的快速散列函数进行很好的研究(当散列数字时报告没有冲突时,请记住它们需要加盐以避免外人猜测)。
128 位输出会产生比 32 位输入所需的更大的 slug。例如,以 base64 表示时,128 位需要最多 24 个字符,而 32 位需要 8 个字符。
要将具有顺序的 32 位 ID 转换为具有密钥的等效不可猜测序列,我建议使用 skip32,它在此处有一个 plpgsql 实现:https ://wiki.postgresql.org/wiki/Skip32
然后可以将这个输出按原样推送到 URL 中(但请注意它已签名)。或者,如果您喜欢 text slug,请将其转换为具有您选择的 int-to-text 可逆转换的 slug。
我会使用 UUID 而不是序列号。有一个模块:https ://www.postgresql.org/docs/current/static/uuid-ossp.html