Diciamo che ho ricevuto 1000 richieste sui nostri server per aggiornare una singola tabella MySQL. I problemi di deadlock si verificano inevitabilmente in questa situazione. Abbiamo tentato nuovamente di postare la transazione come consigliato per deadlock ma si verificano ancora.Il motore MySQL InnoDB accoda automaticamente i trigger DB?
Stiamo pensando di trovare una soluzione alternativa di seguito.
- Crea tabella A, B, C.
- richieste di scrittura vengono al server per aggiornare la tabella D, in A o B o C.
- Creare un trigger INSERT in tabelle A, B e C, rispettivamente, che a sua volta scriverà i dati nella tabella D invece di esporre direttamente la tabella D alle 1000 richieste che giungono al server.
Quindi la nostra domanda è quando questo accade e più righe viene scritto nella tabella A, B e C i trigger sottostanti su tabelle A, B e C possono sparare contemporaneamente aggiornare Tabella D.
Il motore InnoDB di MySQL mette automaticamente in coda questi trigger o dovremmo gestirlo nel nostro codice?
Qualsiasi aiuto è molto apprezzato.
La tabella D che viene aggiornata direttamente da tutte queste richieste ora e dove si verifica il deadlock è simile a questa.
v_user_email varchar(60) NO PRI
v_device_IMEI varchar(40) NO PRI
i_adid int(11) NO PRI
i_impressions int(4) YES 0
dt_pulllogdttm datetime NO
c_created_by char(15) NO
dt_created_on datetime NO
c_modified_by char(15) YES
dt_modified_on datetime YES
PHP che inserisce/aggiorna le righe in questa tabella è come segue. Vedrai che proviamo a postare la transazione 3 volte se fallisce a causa di un deadlock ma ci sono transazioni che falliscono anche in quel momento e il log dice a causa di deadlock.
$updateQuery = "UPDATE tb_ad_pull_log SET i_impressions = (i_impressions + 1), dt_pulllogdttm = SYSDATE(), c_modified_by = '$createdBy', dt_modified_on = SYSDATE() WHERE v_user_email = '$email' AND i_adid = $adId";
if(ExecuteDeadLockQuery($updateQuery, "UPDATE", __LINE__) == 0) // If there is no record for this ad for the user, insert a new record
{
$insertQuery = "INSERT INTO tb_ad_pull_log VALUES('$email', '$device_IMEI', $adId, 1, SYSDATE(), '$createdBy', SYSDATE(), NULL, NULL)";
ExecuteDeadLockQuery($insertQuery, "INSERT", __LINE__);
}
funzione ExecuteDeadLockQuery assomiglia a questo -
function ExecuteDeadLockQuery($query, $activity, $lineNumber)
{
global $errorLoggingPath;
$maxAttempts = 3;
$currentTry = 1;
$noOfAffectedRows = -1;
while($currentTry <= $maxAttempts)
{
$currentTry++;
mysql_query($query);
if(mysql_errno() <> 0) // If error occured
{
continue;
}
else
{
$noOfAffectedRows = mysql_affected_rows();
break;
}
}
if($noOfAffectedRows == -1) // Query never executed successfully
{
LogError($activity . " failed in tb_ad_pull_log: " . mysql_error(), __FILE__, $lineNumber , $errorLoggingPath);
}
return $noOfAffectedRows;
}
C'è un modo più pulito per evitare questo stallo? Ecco alcuni registri che abbiamo.
ERROR: 08-21-2011 14:09:57 UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 83
ERROR: 08-21-2011 14:09:57 INSERT failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 86
ERROR: 08-21-2011 14:09:57 INSERT failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 86
ERROR: 08-21-2011 14:09:57 UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 83
ERROR: 08-21-2011 14:09:57 INSERT failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 86
ERROR: 08-21-2011 14:09:57 UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 83
ERROR: 08-21-2011 14:09:59 UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 83
ERROR: 08-21-2011 14:09:59 UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 83
ERROR: 08-21-2011 14:10:01 UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 83
ERROR: 08-21-2011 14:10:01 INSERT failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 86
La riga 83 è l'istruzione UPDATE nel PHP e 86 è l'INSERT. Si prega di tenere presente che questi dati possono essere scritti in questa tabella al ritmo di 5-8 transazioni al secondo.
Ulteriori informazioni
Con ogni inserimento e aggiornamento nella tabella D un trigger esegue gli aggiornamenti che TAVOLO X e Y. TAVOLA E 'questo un motivo di tabella D di rimanere bloccata e quindi le richieste in arrivo ottiene un deadlock?
Alla fine ho avuto il problema ma non sono sicuro di come risolverlo. I trigger AFTER INSERT e AFTER UPDATE su TABLE D bloccano la tabella quando vengono attivati e quindi il deadlock delle richieste in entrata. Perché sono così sicuro che questo è perché una volta che ho lasciato cadere questi trigger il registro ha interrotto la registrazione dei messaggi deadlock registrati altrimenti
Snippet del codice di trigger.
CREATE DEFINER=CURRENT_USER TRIGGER tuadmin.t_update_CPM_updateBalance
AFTER UPDATE
ON tb_ad_pull_log
FOR EACH ROW
BEGIN
DECLARE `cpm_value` decimal(10,4);
DECLARE `clientid` int(4);
/* Execute the below block if the requested ad is not the default ad */
IF NEW.i_adid <> 1 THEN
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
//do updates to TABLE X and Y logic
END
Questo è dove non capisco perché dovrebbero questi trigger tenere un blocco su Tabella D e non lasciare alcun inserimento/aggiornamento accadere contemporaneamente.
Questo eviterà tutti i problemi se rilasciamo i trigger e richiamiamo semplicemente un SP dal PHP per eseguire il lavoro?
come sono le transazioni? Per avere un deadlock, dovresti avere più di una transazione, che ha già aggiornato una riga e prova ad aggiornare la seconda riga, ma quella riga è stata aggiornata da un'altra transazione. Gli inserti di Simle, così come gli aggiornamenti solo su 1 riga, non causano deadlock. Forse hai bisogno di ordinare per/limitare le tue domande di aggiornamento? –
@Darhazer ha aggiornato la domanda con i dettagli delle transazioni. Il tuo aiuto è molto apprezzato. – Aakash
hai indice su v_user_email/i_adid. In caso contrario, ciò provoca un deadlock, perché la query di aggiornamento deve eseguire la scansione di tutti i record –