我需要在数据库中存储数百万个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)
答案 0 :(得分:10)
根据DNS spec,域名的最大长度为:
DNS本身仅对特定标签施加一个限制 可用于识别资源记录。那一个限制
与标签的长度和全名有关。长度
任何一个标签都限制在1到63个八位字节之间。完整域名
name限制为255个八位字节(包括分隔符)。
255 * 3 = 765< 767(勉强:-))
但请注意,每个组件的长度只能为63个字符。
所以我建议将网址砍成组件位。
这可能就足够了:
这给你一些很好的好处:
答案 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的存在。