2009-06-29 60 views
9

我在计划数据库以存储大量文本。 (博客文章,新闻文章等)数据库需要标题,内容(最多5万个字符),日期,链接和语言字段。同一内容不能在一个链接上发生。旧内容(例如30天以上)将被删除。PostgreSQL:在大型数据库上定义主键

现在,问题是主键。我可以设置一个自动递增(SERIAL类型)字段并将其用作主键。但是,这看起来很愚蠢,并且浪费了光盘空间,因为该领域不会有任何目的,只能成为主要关键。 (并且该字段最终可能会用完,或者不是?)并且总是存在其他性能问题:插入的每个新行的内容都需要检查重复项。因此,我提出的主键的另一个解决方案是计算内容+链接值的sha256散列,然后将其放在新的“散列”列中,并将其用作主键。一石二鸟。当然,这个问题是散列冲突。这是一个很大的威胁吗?

我对PostgreSQL没有任何经验,对DBMS的一般经验也很少,所以我希望在创建一个具有高速公路上蜗牛性能特征的数据库(可怕的比较)之前有第二种意见。

如果您对大型数据库有任何经验,请帮助我。在我的情况下,将64字符的字符串设置为主键字段是个好主意吗? (因为我的印象是,一般这是避免)

回答

9

只是做这个确切的测试相当大中型DB(200GB +),BIGSERIAL由相当大比分获胜。生成速度更快,加入速度更快,代码更少,占地面积更小。由于postgres存储它的方式,bigint与正常int相比可以忽略不计。在您不必担心溢出bigint之前,您的内容中就会耗尽存储空间。完成计算后的散列vs bigint - 一路代替bigint。

2

几点建议:

  • 64位的主键整数的磁盘存储是微不足道的,不管你有多少内容有。
  • 你永远不会碰撞SHA256,并将其作为唯一的ID使用并不是一个坏主意。

哈希方法的一个好处是您没有单个序列源来生成新的主键。如果您的数据库需要以某种方式进行分段(如地理分布)以供将来扩展,那么这很有用,因为您不必担心冲突或产生序列的单点故障。

从编码的角度来看,拥有单个主键对于加入未来可能添加的额外数据表至关重要。我强烈建议你使用一个。对你提出的方法都有好处,但散列方法可能是首选方法,仅仅是因为自动增量/序列值有时会导致可伸缩性问题。

+1

如果您使用SHA256作为主键,它不一定是不可变的吗?如果内容+链接值更改会发生什么? – 2009-06-29 19:37:45

+0

哈维,好点,但如果一个会改变一行的内容值,那么我会检查是否存在新内容+链接alredy的散列。如果是这样,则不会发生变化。 – KRTac 2009-06-29 19:50:25

+0

因此,如果内容发生变化,您创建一个新的记录? – 2009-06-29 20:31:37

1

散列是主键的坏主意。它们使得插入在表中随机排列,因为事物必须重新分配(尽管Postgres实际上并不像其他人那样应用),这会非常昂贵。我建议一个连续的主键,它可能是一个细粒度的时间戳/时间戳,后面跟着连续数字,让你用石头杀死两只鸟,还有第二个包含你的散列码的唯一索引。请记住,您希望将主键保持为较小(64位或更少)的列。

请参阅http://en.wikipedia.org/wiki/Birthday_attack#The_mathematics的表格,以便您确信自己不会碰撞。

不要忘了抽真空。

3

在主键整数用完之前,你必须有很多记录。

连接的整数将比64个字符的字符串主键要快。编写查询的人也更容易处理。

如果碰撞有可能发生,您不能使用散列作为主键。主键必须通过定义以独特的方式进行定义。

我见过数百个生产数据库为不同的公司和政府实体,而不是一个使用哈希主键。认为可能有一个原因?

但是,它似乎很愚蠢和浪费光盘空间,因为该字段不会有任何目的,而是成为主键。

由于代理主键应该总是没有意义,除非作为主键,我不确定你的反对意见是什么。

3

我会选择使用代理键,即。一个不属于您的应用程序业务数据的关键。当您处理每个记录最多50千字节的文本时,额外的64位整数空间要求可以忽略不计。只要您开始将此密钥用作其他表中的外键,您实际上就会使用或更少的空间。

如果散列基于的数据发生更改,则使用存储在记录中的数据的散列是主键的非常糟糕的候选者。然后你将改变主键,如果你有其他表与这个关系的关系,那么你会更新所有地方的更新。

PS。一个类似的问题已经被问到并在这里回答before

下面是关于该主题的另一个很好的写了起来: http://www.agiledata.org/essays/keys.html

1

我会使用普通的32位整数作为主键。我不认为你会很快超过这个数字:-)整个维基百科有大约3,5百万篇文章......如果你每天写1000篇文章,那将需要将近6000年才能达到整数类型的最大值。