L'esempio nella tua domanda mostra che l'ordine di blocco dipende dal metodo di accesso. Questo percorso di accesso non è deciso direttamente dalla clausola ORDER BY della query, ci sono molti fattori che possono influenzare questo percorso di accesso. Pertanto, non puoi prevenire un deadlock semplicemente aggiungendo un ORDER BY perché potresti comunque avere due percorsi di accesso distinti. In effetti, eseguendo il tuo test case con l'ordine e modificando i parametri di sessione, sono stato in grado di eseguire due sessioni in un ORA-60 con la stessa query.
Se le sessioni interessate non hanno altri blocchi in sospeso, blocca le righe nello stesso ordine in tutte le sessioni preverrà deadlock, ma come puoi forzare in modo affidabile questo ordine? Si noti che questo eviterebbe comunque questo caso molto speciale di deadlock. Potresti comunque ottenere deadlock con più query in ogni sessione o piani diversi.
In pratica questo caso è davvero speciale e comunque non dovrebbe succedere spesso:se sei preoccupato per i deadlock, penso comunque che ci siano metodi più semplici per prevenirli.
Il modo più semplice per prevenire un deadlock è utilizzare FOR UPDATE NOWAIT
o FOR UPDATE WAIT X
(sebbene WAIT X possa ancora attivare un deadlock con valori di X superiori al meccanismo di rilevamento del deadlock, attualmente 3 secondi a partire da 11g credo -- grazie @APC
per la correzione).
In altre parole, entrambe le transazioni dovrebbero chiedere:dammi quelle righe e bloccale ma se un altro utente ha già un blocco restituisce un errore invece di aspettare indefinitamente. È l'attesa indefinita che provoca deadlock.
In pratica direi che la maggior parte delle applicazioni con utenti di persone reali preferirebbe ricevere un errore immediatamente piuttosto che una transazione in attesa indefinitamente per il completamento di un'altra transazione. Prenderei in considerazione FOR UPDATE
senza NOWAIT
solo per lavori batch non critici.