2013-08-01 2 views
6

Ich habe eine Tabelle mit Primärschlüssel in Zeichenfolge wie 12a4..., c3af.... Ich möchte, dass sie parallel verarbeiten:Teilen Sie einen Hex-Index in n Stücke

process_them(1,4) on machine 1 
process_them(2,4) on machine 2 
process_them(3,4) on machine 3 
process_them(4,4) on machine 4 

die oben tun müssen wählen alle Zeilen in der Tabelle, ohne Maschinen miteinander zu koordinieren. Die beste Idee, die ich mit oben kommen kann ist sie in 16 wie aufzuspalten:

select * from table where id like '1%' 
... 
select * from table where id like 'e%' 
select * from table where id like 'f%' 

Gibt es eine bessere Idee, die mir mehr Splits wie 1/2 ermöglicht, 1/4, 1/8, 1/16, 1/32 usw. der gesamten Zeilen?

Hinweis: Ich mache dies, um nächtliche Verarbeitung von Benutzerdaten und Senden von Benachrichtigungen zu tun. Ich bearbeite nichts an der DB selbst. Und wir müssen Tausende von Benutzern gleichzeitig verarbeiten, und es kann nicht in einer feinkörnigen Art und Weise aufgeteilt werden, da es auf diese Weise nicht effizient ist.

+0

Wenn die Maschinen eine inkrementierende System-ID haben, könnten sie diese in einer LIMIT-Klausel verwenden. Aber das gilt wahrscheinlich als "koordinierend". IMHO, um etwas besser als das zu erreichen, was Sie vorschlagen, müssen sie etwas über ihre Umwelt wissen. – mabi

+0

Ich denke, verteilte Datenbank ist die beste Lösung. – Suleman

Antwort

0

Der einfachste Ansatz wäre eine status Spalte zu Ihrer Tabelle werden, indem mit mindestens zwei Zuständen:

0 = pending 
1 = *not* pending 

Dann wird jeder Verarbeitungs-Thread der Lage wäre, „Reserve“ eine kleine Charge von Zeilen zu verarbeiten. Der allgemeine Arbeitsablauf wäre:

BEGIN TRANSACTION; 
SELECT * FROM queue WHERE status = 0 LIMIT 5 FOR UPDATE; -- load 5 pending items 
-- if no pending item: terminate here 
-- save this list of jobs in your application layer here 
UPDATE queue SET status = 1 WHERE id IN (@id_list); -- list of id's from the previous step 
COMMIT; 
-- process your jobs here 
-- loop 

Abhängig von der tatsächlichen Bearbeitungszeit Ihrer Jobs, ist dieser Ansatz zu schwer einen Overhead kann zufriedenstellend. Erhöhen Sie den Wert LIMIT im ersten Schritt, um mehr Jobs gleichzeitig zu laden, um den relativen Overhead auf Kosten einer möglicherweise weniger ausgeglichenen Verteilung von Jobs über die Prozesse hinweg zu senken.

+0

Wir aktualisieren die Daten nicht selbst. Und das gleichzeitige 'select for update' würde sich gegenseitig sperren bis zum Commit/Abbruch. Es wird nicht parallel gemacht werden. – aitchnyu

+0

Nein, im schlimmsten Fall würden gleichzeitige Threads nur für die Zeit gesperrt, die ein Thread benötigt, um Jobs zu laden und deren Status zu aktualisieren ('SELECT' und' UPDATE'), dh einige Millisekunden, wenn die Tabelle korrekt ist indexiert. Beachten Sie, dass der Teil "Ihre Jobs hier bearbeiten" außerhalb der Transaktion liegt. Ich bin nicht sicher, dass das Hinzufügen und Bearbeiten einer neuen Spalte für Ihre Operation nur als "Ändern der Daten selbst" betrachtet werden sollte, aber ich verstehe, dass dies in einigen Fällen ein No-Go sein kann. – RandomSeed

2

Nette Idee ...

können Sie einen MD5-Hash verwenden, um die Zeilen in einer angemessenen Art und Weise gut verteilt schnell distrubute, consitently und ohne DDL-Änderungen (Es wird nie eine verpasste Reihe sein).

*let n = number of desired partitions. Use the following sql to 
*let s = salt, expirementally chosen to provide the best distribution based on key allocation pattern. 
SELECT * FROM TABLE WHERE mod(cast(conv(md5(concat(s, Priamry_Key)), 16, 10), n) = 0; 
SELECT * FROM TABLE WHERE mod(cast(conv(md5(concat(s, Priamry_Key)), 16, 10), n) = 1; 
... 
... 
SELECT * FROM TABLE WHERE mod(cast(conv(md5(concat(s, Priamry_Key)), 16, 10), n) = (n-1); 

Dies ist ein Ansatz, den ich einige Male in Produktionsumgebungen mit guten Ergebnissen implementiert habe.

Die SQL hier ist nicht getestet Ich mache keine Gaurantees auf Sytax.

Verwandte Themen