Question

J'ai une énorme liste d'URL dans une table MySQL InnoDB, et les processus de travail qui interrogent MySQL pour un ensemble d'URL à traiter. Les URL doivent immédiatement être marqués comme étant traités, de sorte que d'autres processus de travail ne gaspillent pas les ressources en commençant à traiter les mêmes.

Actuellement, je fais d'abord pour obtenir des URL:

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

Ensuite, dans le code I naïve boucle à travers chacune de ces URL pour la marquer comme en cours de traitement:

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

Je suis parfaitement conscient comment cela est stupide et inefficace. Plus important encore, il n'y a aucune garantie qu'un autre processus de travail ne serait pas essayer d'obtenir une liste au milieu de mes Updates. Quelle est la belle façon de le faire? Dois-je faire une transaction, comment?

Était-ce utile?

La solution

Le message suivant apparaît (par un rapide coup d'œil au manuel MySQL 5) être disponible en MySQL; Je ne suis pas sûr que ce soit la meilleure approche, mais il est celui que je l'ai utilisé auparavant dans 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;

En fait, dans PostgreSQL j'utiliser un à instruction UPDATE avec la clause RENVOYER prenant la place UPDATE du SELECT, mais qui est une extension spécifique à PostgreSQL.

Un problème potentiel que je vois avec votre approche est double URL: si l'URL apparaît deux fois dans http://www.example.com/ votre table, disent avec les ID 23 et 42, il se revient avec l'un de ces deux pièces d'identité par le SELECT, mais la mise à jour affecter les deux lignes. Je ne sais pas si ce comportement est logique dans votre application; Je serais probablement mis une sorte de contrainte UNIQUE sur les URL de sorte qu'il ne pouvait pas se produire, puis utiliser une liste d'ID, pas les URL, dans la clause IN (qui devrait être plus rapide).

Autres conseils

Peut-être que vous devriez simplement sélectionner toutes les URL d'abord et ensuite utiliser les threads pour les analyser de manière asynchrone?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top