Sto cercando un modo per selezionare esplicitamente una riga di tabella per un thread. Ho scritto un crawler, che funziona con circa 50 processi paralleli. Ogni processo deve prendere una riga da un tavolo ed elaborarla.Selezionare una sola riga di tabella su connessioni parallele alte
CREATE TABLE `crawler_queue` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`url` text NOT NULL,
`class_id` tinyint(3) unsigned NOT NULL,
`server_id` tinyint(3) unsigned NOT NULL,
`proc_id` mediumint(8) unsigned NOT NULL,
`prio` tinyint(3) unsigned NOT NULL,
`inserted` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `proc_id` (`proc_id`),
KEY `app_id` (`app_id`),
KEY `crawler` (`class_id`,`prio`,`proc_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
Ora i miei processi di effettuare le seguenti operazioni:
- transazione inizio DB
- fare un selezionato come
SELECT * FROM crawler_queue WHERE class_id=2 AND prio=20 AND proc_id=0 ORDER BY id LIMIT 1 FOR UPDATE
- quindi aggiornare questa riga con
UPDATE crawler_queue SET server_id=1,proc_id=1376 WHERE id=23892
- commit della transazione
Ciò dovrebbe aiutare che nessun altro processo può afferrare una riga ancora elaborata. Facendo un EXPLAIN sui spettacoli selezionati
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE crawler_queue ref proc_id,crawler proc_id 3 const 617609 Using where
Ma i processi sembrano causare troppo elevato parallelismo, perché a volte riesco a vedere due tipi di errori/avvisi nel mio log (ogni 5 minuti o giù di lì):
mysqli::query(): (HY000/1205): Lock wait timeout exceeded; try restarting transaction (in /var/www/db.php l
ine 81)
mysqli::query(): (40001/1213): Deadlock found when trying to get lock; try restarting transaction (in /var/www/db.php line 81)
La mia domanda è: qualcuno può indicarmi la giusta direzione per minimizzare questi problemi di blocco? (In stato di produzione, il parallelismo sarebbe 3-4 volte superiore a quello ora, quindi assumere, che ci sarebbero problemi molto più bloccaggio)
EDIT 2012/12/29: Ho modificato SELECT
usare indice crawler
dal suggerimento USE INDEX(crawler)
. Il mio problema ora è più timeout di lockwait (deadlock sono scomparsi).
EDIT 2012-12-31: EXPLAIN
con USE INDEX()
mostra ora (non di righe è più alto, perché la tabella contiene più dati ora.):
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE crawler_queue ref proc_id,crawler crawler 5 const,const,const 5472426 Using where
Bella idea, ma 'LAST_INSERT_ID()' restituirà un valore solo se i dati 'INSERT' o' UPDATE' incrementano la colonna autoincrement: ** EDIT ** Darò http://stackoverflow.com/questions/ 1388025/how-to-get-id-of-the-last-updated-row-in-mysql a prova – rabudde
Per qualche motivo ho ottenuto un valore last_insert_id quando ho provato, ma mi ha ingannato (sembrava quello giusto, ma non lo era). Credo che la soluzione descritta in questa domanda sia la strada da seguire. Aggiornerò anche la mia risposta – Xnoise