我正在计划一个数据库来存储大量文本。 (博客文章,新闻文章等)数据库需要有标题,内容(最多50k字符),日期,链接和语言字段。在一个链接上不能发生相同的内容。旧内容(例如,早于30天)将被删除。
现在,问题是主键。我可以设置一个自动递增(SERIAL类型)字段并将其用作主键。但是,它似乎是愚蠢的,浪费了磁盘空间,因为该领域不会用于任何目的,而是成为主键。 (并且该字段最终可能会耗尽?或者总是存在其他性能问题:插入的每个新行的内容都需要检查重复项。因此,我提出的主键的另一个解决方案是计算内容+链接值的sha256哈希,然后将其放入新的“哈希”列并将其用作主键。一石二鸟。当然,问题是哈希冲突。这是一个很大的威胁吗?
我对PostgreSQL没有任何经验,而且对DBMS的经验也很少,所以在创建一个具有高速公路蜗牛性能特征的数据库之前,我会很感激第二意见(可怕的比较)。 p>
如果您有大型数据库的经验,请在这里帮助我。在我的情况下,将64个字符的字符串设置为主键字段是个好主意吗? (因为我的印象是通常会避免这种情况)
答案 0 :(得分:9)
对于一个相当中等大小的数据库(200GB +)这个确切的测试,bigserial赢得了相当大的差距。生成速度更快,加入速度更快,代码更少,占用空间更小。由于postgres存储它的方式,与普通int相比,bigint可以忽略不计。在您不必担心溢出bigint之前,您的内容将耗尽存储空间。完成计算的哈希与bigint - 代理bigint一路。
答案 1 :(得分:4)
我会选择使用代理键,即。不属于应用程序业务数据的密钥。当您处理每条记录高达50千字节的文本时,额外的64位整数的额外空间要求可以忽略不计。一旦您开始将此密钥用作其他表中的外键,您实际上将使用 less 空间。
如果散列所基于的数据发生变化,则使用存储在记录中的数据的散列是主键的非常糟糕的候选者。然后,您也将更改主键,如果您从其他表到此表有关系,则会在整个地方进行更新。
PS。在before http://www.agiledata.org/essays/keys.html已经提出并回答了类似的问题。
这是关于该主题的另一篇很好的文章: {{3}}
答案 2 :(得分:3)
在主键整数用完之前,你必须拥有大量的记录。
对于连接,整数将比64字符串主键更快。编写查询的人也更容易处理。
如果可能发生冲突,则不能将哈希用作主键。主键必须通过定义来保证是唯一的。
我已经看到数百个不同公司和政府实体的生产数据库,而不是一个使用哈希主键。认为可能有原因?
但是,它似乎是愚蠢的,浪费了光盘空间,因为该领域不会用于任何目的,而是成为主键。
由于代理主键除了作为主键外应该总是没有意义,因此我不确定你的异议是什么。
答案 3 :(得分:2)
一些建议:
哈希方法的一个好处是你没有单个序列源来生成新的主键。如果您的数据库需要以某种方式(例如地理分布)进行分段以便将来扩展,这可能很有用,因为您不必担心冲突,或者生成序列的单点故障。
从编码的角度来看,拥有一个主键对于加入您将来可能添加的额外数据表至关重要。我强烈建议你使用一个。您提出的方法都有好处,但哈希方法可能是首选方法,因为自动增量/序列值有时会导致可伸缩性问题。
答案 4 :(得分:1)
哈希是主键的坏主意。它们使得插入在表中以随机顺序结束,并且由于必须重新分配,所以这会非常昂贵(尽管Postgres并不像其他人那样真正应用)。我建议一个顺序主键,它可以是一个细粒度的时间戳/时间戳,后面跟着序号,让你用一块石头杀死两只鸟,另一个包含你的哈希码的唯一索引。请记住,您希望将主键保持为较小的(64位或更少)列。
请参阅http://en.wikipedia.org/wiki/Birthday_attack#The_mathematics上的表格,以便您确信不会发生碰撞。
不要忘记吸尘。
答案 5 :(得分:1)
我会使用普通的32位整数作为主键。我不认为你会很快超过这个数字:-)整个维基百科有大约3,5百万篇文章......如果你每天写1000篇文章,那么将需要将近6000年才能达到整数类型的最大值。