我在写一个需要处理数百万个URL的应用程序。它还需要通过URL进行检索。在没有唯一索引/约束的MySQL中防止重复行?
我的表目前看起来是这样的:
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散列做一下UPS,因为B-tree索引将是对趋于网址非常低效有共同的前缀(InnoDB不支持散列索引)。通过与完整URL进行比较来过滤来自CRC32的重复结果。示例检索查询将如下所示:
SELECT id
FROM Pages
WHERE url_crc = 2842100667
AND url = 'example.com/page.html';
我遇到的问题是避免重复的条目被插入。应用程序将始终在插入新条目之前检查数据库中的现有条目,但在我的应用程序中,可能会同时对同一个新的URL进行多个查询,并且会输入重复的CRC32和URL。
我不想在url上创建唯一的索引,因为它将是巨大的。我也不想在每次插入时锁定表,因为这会破坏并发插入性能。有没有一种有效的方法来解决这个问题?
编辑:为了更详细地了解使用情况,这是一个实时查找内容以响应URL的表格。通过查找URL,我可以找到URL的内部标识,然后使用它来查找页面的内容。新的URL会一直添加到系统中,我不知道这些URL会在什么时候发布。当引用新的URL时,它们很可能会被引用相同URL的同时请求(可能每秒数百次)抨击,这就是为什么我在添加新内容时担心竞争条件的原因。结果需要是立即的,不能有读滞后(亚秒延迟是好的)。
首先,每天只会新增几千个网址,但在明年我们有时间转移到更具扩展性的解决方案之前,系统需要处理很多次。
在url上使用唯一索引的另一个问题是URL的长度可能超过唯一索引的最大长度。即使我放弃CRC32技巧,也不能解决防止重复URL的问题。
如何存储网址(sha1?)的散列副本并索引该字段?使用适当的数据库触发器来更新/填充插入/更新散列时,维护开销将非常小。 –
CRC32是URL的散列。它比SHA1小得多(4个字节与20个字节)。我正在计算它在应用程序方面。 –
确实如此,但只有32位,你大大增加了碰撞的可能性,并因此导致误报。 –