我在MySQL InnoDB表中有大量的URL列表,并且可以对MySQL进行查询的工程处理是否要处理一组URL。应该立即将URL标记为处理,以便其他工作过程不会通过处理相同的过程来浪费资源。

目前,我首先这样做以获取一些URL:

SELECT DISTINCT url FROM urls WHERE task_assigned is NULL ORDER BY id LIMIT 100

然后在代码中天真地循环遍历每个URL,以将其标记为处理:

UPDATE urls SET task_assigned = NOW() WHERE url = ? COLLATE utf8_bin

我完全意识到这是多么愚蠢和效率低下。更重要的是,不能保证另一个工作流程不会尝试在我的更新中间获取列表。这样做的美丽方法是什么?我应该做交易,如何?

有帮助吗?

解决方案

下面出现(快速浏览MySQL 5手册),可在MySQL中使用;我不确定这是否是最好的方法,但我以前在PostgreSQL中使用过:

BEGIN TRANSACTION;
SELECT DISTINCT url FROM urls WHERE task_assigned is NULL ORDER BY id LIMIT 100 FOR UPDATE;
UPDATE urls SET task_assigned = NOW() WHERE url IN [list of URLs] COLLATE utf8_bin;
COMMIT;

实际上,在Postgresql中,我会使用 单身的 更新语句带有更新的返回子句,取代了Select的代替,但这是一个特定于PostgreSQL的扩展名。

我在您的方法中看到的一个潜在问题是重复的URL:如果URL http://www.example.com/ 出现在您的表中两次,例如IDS 23和42,它将通过SELECT返回这两个ID之一,但更新会影响两个行。我不知道这种行为在您的应用程序中是否有意义;我可能会对URL放置某种独特的约束,以免发生,然后在该URL中使用ID列表,而不是URL列表 IN 条款(应该更快)。

其他提示

也许您应该首先选择所有URL,然后使用线程使它们异步解析?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top