mysql - 如何在 MySQL 中存储 URL

标签 mysql

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

但是,我无法在 URL 字段上创建索引,因为我的 varchar 字段是 400 个字符。 MySQL在提示和说; “#1071 - 指定的 key 太长;最大 key 长度为 767 字节”。 (Varchar 400 将占用 1200 个字节)

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

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

有没有其他可能使用更少的资源和时间来做到这一点。我正在考虑获取 URL 的 MD5 哈希并存储它。我可以使该字段成为唯一的。我知道,会有冲突,但如果这是唯一的问题,那么在 1 亿个 URL 中有 5-10-20 个重复是可以的。

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

你有什么建议?

编辑:根据请求,这是表定义。 (我暂时不用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)

最佳答案

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

The DNS itself places only one restriction on the particular labels
that can be used to identify resource records. That one restriction
relates to the length of the label and the full name. The length of
any one label is limited to between 1 and 63 octets. A full domain
name is limited to 255 octets (including the separators).

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

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

所以我建议将 url 切成组件位。

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

这可能就足够了:

  • 协议(protocol)标志 ["http"-> 0 ](将 "http"存储为 0,将 "https"存储为 1,等等)
  • 子域 [“foo”](255 - 63 = 192 个字符:我可以再减去 2 个字符,因为 min tld 是 2 个字符)
  • 域 [“示例”],(63 个字符)
  • tld ["com"](4 个字符来处理 "info"tld)
  • path [ "a/really/long/path"](只要你想 -存储在单独的表中)
  • queryparameters ["with=lots&of=query¶meters=that&goes=on&forever&and=ever"](存储在单独的键/值表中)
  • 如果实际需要,很少使用的端口号/身份验证内容可以放在单独的键控表中。

这为您提供了一些不错的优势:

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

关于mysql - 如何在 MySQL 中存储 URL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6800866/

相关文章:

php - MYSQL PHP 通配符

mysql - 将mysql 5.5降级到mysql 5.0或5.1会导致数据丢失吗?

php - 提取数据并将其打印在 HTML 表格中

c# - 尽管数据库中有数据,MySQL 查询数据检索却给出所有内容为空

python - 在内存高效生成器中使用 PyMySql 的正确方法

PHP artisan循环数组错误

MYSQL 服务器在 100 万条记录上运行查询非常慢

mysql - 将适用于一行的 SQL 查询应用于所有行

php - 从 MySQL 存储和检索 $_GET 语句

MySQL:连续时间内可用的时间跨度