如何在MySQL中存储URL

时间:2011-07-23 14:00:03

标签: mysql

我需要在数据库中存储数百万个URL。每个URL都应该是唯一的,因此我将使用ON DUPLICATE KEY UPDATE并计算重复的URL。

但是,我无法在URL字段上创建索引,因为我的varchar字段是400个字符。 MySQL抱怨并说; "#1071 - 指定密钥太长;最大密钥长度为767字节"。 (Varchar 400将占用1200字节)

如果您需要在一台服务器中每天处理至少500000个网址,最好的方法是什么?

我们已经在考虑将MongoDB用于同一个应用程序,因此我们可以简单地查询MongoDB并找到重复的URL,并更新该行。但是,我并不赞成使用MongoDB来解决这个问题,而且我想在这个阶段使用MySQL,因为我希望在开始时尽可能精简并完成本节的项目要快得多。 (我们还没有和MongoDB玩过,也不想在这个阶段花时间)

使用更少的资源和时间是否还有其他可能性。我想要获取URL的MD5哈希并存储它。而且我可以将该字段改为UNIQUE。我知道,会有冲突,但如果这是唯一的问题,那么在1亿个网址中可以有5-10-20个重复项。

你有什么建议吗?我也不想花10秒钟只插入一个网址,因为它每天会处理500,000个网址。

你会建议什么?

编辑:根据请求,这是表定义。 (我目前不使用MD5,而是用于测试)

mysql> DESC url;
+-------------+-----------------------+------+-----+-------------------+-----------------------------+
| Field       | Type                  | Null | Key | Default           | Extra                       |
+-------------+-----------------------+------+-----+-------------------+-----------------------------+
| url_id      | int(11) unsigned      | NO   | PRI | NULL              | auto_increment              |
| url_text    | varchar(400)          | NO   |     |                   |                             |
| md5         | varchar(32)           | NO   | UNI |                   |                             |
| insert_date | timestamp             | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| count       | mediumint(9) unsigned | NO   |     | 0                 |                             |
+-------------+-----------------------+------+-----+-------------------+-----------------------------+
5 rows in set (0.00 sec)

5 个答案:

答案 0 :(得分:10)

根据DNS spec,域名的最大长度为:

  

DNS本身仅对特定标签施加一个限制   可用于识别资源记录。那一个限制
  与标签的长度和全名有关。长度
  任何一个标签都限制在1到63个八位字节之间。完整域名
  name限制为255个八位字节(包括分隔符)。

255 * 3 = 765< 767(勉强:-))

但请注意,每个组件的长度只能为63个字符。

所以我建议将网址砍成组件位。

使用http://foo.example.com/a/really/long/path?with=lots&of=query&parameters=that&goes=on&forever&and=ever

这可能就足够了:

  • 协议标志[“http” - > 0](将“http”存储为0,将“https”存储为1等)
  • 子域名[“foo”](255 - 63 = 192个字符:我可以减去2个,因为min tld是2个字符)
  • domain [“example”],(63个字符)
  • tld [“com”](处理“info”tld的4个字符)
  • 路径[“a / really / long / path”](只要您愿意 - 存储在单独的表中
  • queryparameters [“with = lots& of = query& parameters = that& goes = on& forever& and = ever”]( 存储在单独的键/值表中
  • portnumber /身份验证很少使用的东西可以在一个单独的键控表中,如果实际需要的话。

这给你一些很好的好处:

  • 索引仅在您需要搜索的网址部分(较小的索引!)
  • 查询可以限于各种网址部分(例如,查找facebook域中的每个网址)
  • 任何具有太长子域名/域名的网址都是伪造的
  • 易于放弃查询参数。
  • 易于执行不区分大小写的域名/ tld搜索
  • 丢弃语法糖(协议后的“://”,子域/域之间的“。”,域/ tld,tld和路径之间的“/”,查询前的“?”,“&”“=”in查询)
  • 避免主要的稀疏表问题。大多数网址不具有查询参数,也不具有长路径。如果这些字段位于单独的表中,那么您的主表将不会占用大小。在进行查询时,更多记录将适合内存,因此查询性能更快。
  • (这里有更多优点)。

答案 1 :(得分:0)

要将字段索引到767个字符宽,它的charset必须是ascii或类似的,它不能是utf8,因为它每个字符使用3个字节,因此索引的utf-8字段的最大宽度为255

当然,一个767 ascii url字段,超出了你最初的400个字符规范。当然,有些网站超出了767的限制。也许你可以存储和索引前735个字符加上md5哈希。您还可以使用 text full_url字段来保留原始值 请注意,ascii charset对于网址来说已经足够了

答案 2 :(得分:0)

格式良好的URL只能包含ASCII范围内的字符 - 需要对其他字符进行编码。因此,假设您要存储的URL格式正确(如果不是,您可能希望在将它们插入数据库之前修复它们),您可以将url_text列字符集定义为ASCII(MySQL中的latin1)。使用ASCII,一个字符是一个字节,您可以按照自己的意愿索引整个400个字符。

答案 3 :(得分:0)

与MD5(128位)发生虚假冲突的几率可以用这种方式表达:

“如果你有9万亿个不同的物品,那么其中有两个拥有相同的MD5只有一个机会。”

换句话说,它更有可能在赢得大型彩票时被流星击中。

答案 4 :(得分:-1)

您可以将url_text从VarChar(400)更改为Text,然后您可以为其添加全文索引,以便在插入之前搜索URL的存在。