正确使用MySQL将任务分配给工作流程的方法
-
21-08-2019 - |
题
我在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,然后使用线程使它们异步解析?
不隶属于 StackOverflow