【发布时间】:2011-10-11 19:33:04
【问题描述】:
我正在编写一个需要处理数百万个 URL 的应用程序。它还需要通过 URL 进行检索。
我的桌子目前是这样的:
CREATE TABLE Pages (
id bigint(20) unsigned NOT NULL,
url varchar(4096) COLLATE utf8_unicode_ci NOT NULL,
url_crc int(11) NOT NULL,
PRIMARY KEY (id),
KEY url_crc (url_crc)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
这种结构背后的想法是通过 URL 的 CRC32 散列进行查找,因为 b-tree 索引在具有公共前缀的 URL 上效率非常低(InnoDB 不支持散列索引)。 CRC32 中的重复结果通过与完整 URL 的比较进行过滤。示例检索查询如下所示:
SELECT id
FROM Pages
WHERE url_crc = 2842100667
AND url = 'example.com/page.html';
我遇到的问题是避免插入重复的条目。应用程序总是会在插入新条目之前检查数据库中的现有条目,但在我的应用程序中,可能会同时对同一个新 URL 进行多个查询,并且会输入重复的 CRC32 和 URL。
我不想在 url 上创建唯一索引,因为它会很大。我也不想在每次插入时都锁定表,因为这会破坏并发插入性能。有没有有效的方法来解决这个问题?
编辑:为了更详细地了解使用情况,它是一个用于查找内容以响应 URL 的实时表。通过查找 URL,我可以找到 URL 的内部 id,然后使用它来查找页面的内容。新的 URL 一直被添加到系统中,我不知道这些 URL 会是什么。当引用新的 URL 时,它们可能会被同时引用相同 URL 的请求猛烈抨击,可能每秒数百次,这就是为什么我在添加新内容时担心竞争条件的原因。结果需要立竿见影,不能有读取延迟(亚秒级延迟是可以的)。
首先,每天将仅添加几千个新 URL,但系统需要处理多次,我们才有时间在明年转向更具可扩展性的解决方案。
仅在 url 上使用唯一索引的另一个问题是 URL 的长度可能超过唯一索引的最大长度。即使我放弃了 CRC32 技巧,它也不能解决防止重复 URL 的问题。
【问题讨论】:
-
如何存储 url (sha1?) 的散列副本并索引该字段?在数据库上使用适当的触发器来更新/填充插入/更新时的哈希,维护开销将非常小。
-
CRC32 是 URL 的哈希值。它只是比 SHA1 小得多的散列(4 个字节对 20 个字节)。我在应用程序端计算它。
-
是的,但只有 32 位,你大大增加了碰撞的几率,因此误报了。
-
您能否提供更多有关如何使用该表的信息?例如,如果您正在记录 URL 以供以后进行详细分析,则暂时有重复的条目并在以后剔除它们可能是可以接受的。如果您还要实时从表中读取,那么读取表在条目之后滞后一小段时间是否可以接受(即条目在输入时转到另一个表并且读取表每分钟更新一次)?
-
数百万个 URL 不会创建一个“巨大”的索引。十亿个 URL 可能会创建一个相当大的索引。
标签: mysql sql query-optimization