存储URL的最佳主键

时间:2010-09-17 12:43:57

标签: mysql database-design primary-key

哪个是存储网站地址和网页网址的最佳主键?

为了避免使用自动增量id(它与数据没有真正联系),我使用URL的SHA1签名作为主键设计了模式。

这种方法在很多方面都很有用:例如,我不需要从数据库中读取last_id,因此我可以准备计算密钥的所有表更新,并在单个事务中进行真正的更新。没有违反约束。

无论如何,我读了两本书,告诉我我错了。在“高性能MySQL”中,据说随机密钥对DB优化器不利。此外,在Joe Celko的每本书中,他都说主键应该是数据的一部分。

问题是:URL的自然键是...... URL本身。事实上,如果一个网站很短(www.something.com),那么am URL就没有强制限制(见http://www.boutell.com/newfaq/misc/urllength.html)。

考虑一下我必须存储(并使用)数百万个。

哪个是最好的钥匙呢?自动增量ID,网址,网址哈希?

3 个答案:

答案 0 :(得分:16)

您需要一个自动增量数字主键。对于需要传递ID或连接其他表的时间(例如,URL的可选属性),您需要一些小而且数字的东西。

至于你想要的其他列和索引,它一如既往地取决于你将如何使用它们。

存储每个URL哈希的列对于几乎所有使用大量URL的应用程序来说都是一个很好的主意。它使得通过其全文选择一个URL的速度与它将获得的速度一样快。第二个优点是,如果您将该列设置为UNIQUE,则无需担心使存储实际URL的列唯一,您可以使用REPLACE INTO和INSERT IGNORE作为简单,快速的原子写操作。

我想补充一点,使用MySQL的内置MD5()函数就可以了。它唯一的缺点是专门的攻击者可以强制进行冲突,我很确定你并不关心。例如,使用内置函数可以更轻松地实现某些类型的连接。通过网络传递完整的URL可能会慢一点(“SELECT url FROM urls WHERE hash = MD5('verylongurl')”而不是“WHERE hash ='32charhexstring'”),但你可以选择如果你想要这样做。除非你能想出一个MD5()让你失望的具体场景,否则随时可以使用它。

难以理解的问题是,您是否以及如何以非完整文本的方式查找网址:例如,您是否希望在任何“bar.com”上找到以“/ foo”开头的所有网址“主持人?虽然“LIKE'%bar.com%/ foo%'”将用于测试,但它将在规模上惨败。如果您的需求包含类似的内容,您可以提出创造性的方法来生成针对您需要的数据类型的非UNIQUE索引...对于初学者来说可能是domain_name列。你必须从你的应用程序中填充这些列,几乎可以肯定(触发器和存储过程比它们在这里值得多麻烦,特别是如果你关心性能 - 不要打扰)。

好消息是关系数据库对于这类事情非常灵活。您始终可以添加新列并在以后填充它们。我建议初学者:int unsigned auto_increment主键,唯一散列字符(32)和(假设64K字符就足够了)文本URL。

答案 1 :(得分:2)

大概你在谈论一个完整的URL,而不只是一个主机名,包括CGI参数和其他东西。

SHA-1散列网址使得所有密钥都很长,并且排序麻烦相当模糊。我不得不在哈希上使用索引来隐藏一些机密数据,同时保持连接两个表的能力,而且性能很差。

有两种可能的方法。一个是天真而明显的;它实际上在mySQL中运行良好。它具有诸如简单性和使用URL LIKE'无论%'来有效搜索的优点。

但是如果你有很多网址集中在几个域......例如......

http://stackoverflow.com/questions/3735390/best-primary-key-for-storing-urls
http://stackoverflow.com/questions/3735391/how-to-add-a-c-compiler-flag-to-extconf-rb

等等,您正在查看仅在最后一个字符中有所不同的索引。在这种情况下,您可以考虑存储和索引URL,使其字符顺序颠倒过来。这可能会导致更有效地访问索引。

(Oracle表服务器产品的内置方式是使用所谓的反向索引进行此操作。)

如果我是你,我会避免使用自动增量键,除非你必须加入两个以上的表ON TABLE_A.URL = TABLE_B.URL或其他一些连接条件。

答案 2 :(得分:1)

取决于您如何使用该表。如果您主要选择WHERE url='<url>',那么可以使用单列表。如果您可以使用自动增量ID来识别应用中所有位置的网址,请使用自动增量