Mysql 存储URL的最佳主键

Mysql 存储URL的最佳主键,mysql,database-design,primary-key,Mysql,Database Design,Primary Key,哪个是存储网站地址和页面URL的最佳主键 为了避免使用autoincremental id(它并没有真正与数据绑定),我设计了使用URL的SHA1签名作为主键的模式 这种方法在许多方面都很有用:例如,我不需要从数据库中读取最后一个_id,这样我就可以准备所有表更新,计算键,并在单个事务中执行真正的更新。没有违反约束 不管怎样,我读了两本书,它们告诉我我错了。在“高性能MySQL”中,有人说随机密钥不适合DB优化器。此外,在乔·塞尔科的每一本书中,他都说主要的关键应该是数据的某一部分 问题是:UR

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

为了避免使用autoincremental id(它并没有真正与数据绑定),我设计了使用URL的SHA1签名作为主键的模式

这种方法在许多方面都很有用:例如,我不需要从数据库中读取最后一个_id,这样我就可以准备所有表更新,计算键,并在单个事务中执行真正的更新。没有违反约束

不管怎样,我读了两本书,它们告诉我我错了。在“高性能MySQL”中,有人说随机密钥不适合DB优化器。此外,在乔·塞尔科的每一本书中,他都说主要的关键应该是数据的某一部分

问题是:URL的自然键是。。。URL本身。事实上,如果一个网站的网址很短(www.something.com),那么am URL就没有强加的限制(请参阅)

想想看,我必须存储(并与之合作)数百万个


那么,哪把钥匙最好?自动增量ID、URL、URL哈希?

取决于您如何使用该表。如果您主要使用
选择,其中url='
,则可以使用一列表。如果您可以使用autoincrement id在应用程序中的所有位置标识URL,那么使用autoincrement可以推测您指的是整个URL,而不仅仅是主机名,包括CGI参数和其他内容

SHA-1对URL进行散列会使所有键都很长,并且使排序问题变得相当模糊。我曾经不得不在哈希表上使用索引来隐藏一些机密数据,同时保持连接两个表的能力,而且性能很差

有两种可能的方法。一个是幼稚而明显的;它实际上在mySQL中工作得很好。它的优点是简单,并且能够使用像“whatever%”这样的URL高效搜索

但是如果你有很多URL集中在几个域中。。。例如

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 table server产品有一种内置的方法,即所谓的反向索引。)


如果我是你,我会避免使用自动递增键,除非你必须在TABLE_A.URL=TABLE_B.URL上连接两个以上的TABLE
,或者其他类似的连接条件。

你需要一个自动递增数字主键。当您需要传递ID或与其他表(例如URL的可选属性)连接时,您需要一些小的数字

至于您还需要哪些列和索引,这取决于您将如何使用它们

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

我想补充一点,使用MySQL的内置MD5()函数就可以达到这个目的。它唯一的缺点是,一个专门的攻击者可以强制冲突,我敢肯定你不会在意。例如,使用内置函数可以使某些类型的联接更容易。通过网络传递完整的URL可能会稍微慢一点(“从URL中选择URL,其中hash=MD5('verylongurl')”而不是“WHERE hash='32charhexstring')),但如果需要,您可以选择这样做。除非你能想出一个MD5()会让你失望的具体场景,否则你可以随意使用它

困难的问题是,您是否需要以及如何以非全文的方式查找URL:例如,您是否希望在任何“bar.com”主机上查找所有以“/foo”开头的URL?虽然“像'%bar.com%/foo%'”可以在测试中工作,但它在规模上会失败得很惨。如果您的需要包括这样的内容,您可以想出创造性的方法来生成针对您需要的数据类型的非唯一索引。。。首先,可能是一个域名栏。几乎可以肯定的是,您必须从应用程序中填充这些列(触发器和存储过程比它们在这里的价值要麻烦得多,特别是如果您关心性能的话——不用麻烦)


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

我认为这在很大程度上取决于您对这些url、访问模式等所做的其他操作。使用SHA1应该不会发生冲突,因为较短的哈希函数(例如CRC32)可以避免冲突这显然是不合适的,但冲突仍然可能发生,你只是运气不好。+1-使用更宽的基本密钥会对性能产生严重影响,SQL团队有很好的文档记录,大多数开发人员都忽略了这一点。为什么要将哈希存储为十六进制而不是十进制形式?提高哈希连接性能的一种方法是添加第二个索引列,其中包含更“集中”的哈希数据版本。具有MD5的前64位的BIGINT可以比CHAR(32)更有效地进行索引。碰撞将是更为常见的无数倍,也就是说,极其罕见。WHERE可以在两个列上进行连接(“WHERE t1.inthash=t2.inthash和t1.charhash=t2.charhash”),在极为罕见的BIGINT冲突情况下,完整的哈希将确保您仍然得到正确的答案。