Oracle
 sql >> Database >  >> RDS >> Oracle

L'aggiornamento SQL influirà sulla sua sottoquery durante l'esecuzione dell'aggiornamento?

** Modificato **

Selezione dalla tabella di destinazione

Dal 13.2.9.8. Subquery nella clausola FROM:

Le sottoquery nella clausola FROM possono restituire uno scalare, una colonna, una riga o una tabella. Le sottoquery nella clausola FROM non possono essere sottoquery correlate, a meno che non vengano utilizzate all'interno della clausola ON di un'operazione JOIN.

Quindi, sì, puoi eseguire la query di cui sopra.

Il problema

Ci sono davvero due problemi qui. C'è concorrenza o garanzia che nessun altro modifichi i dati da sotto i nostri piedi. Questo viene gestito con il blocco. La gestione dell'effettiva modifica dei valori nuovi rispetto a quelli precedenti viene gestita con tabelle derivate.

Blocco

Nel caso della tua query sopra, con InnoDB, MySQL esegue prima SELECT e acquisisce un blocco di lettura (condiviso) su ciascuna riga della tabella individualmente. Se avessi una clausola WHERE nell'istruzione SELECT, solo i record selezionati verrebbero bloccati, mentre gli intervalli causerebbero il blocco di eventuali spazi vuoti.

Un blocco di lettura impedisce a qualsiasi altra query di acquisire blocchi di scrittura, quindi i record non possono essere aggiornati da un'altra parte mentre sono bloccati in lettura.

Quindi, MySQL acquisisce un blocco di scrittura (esclusivo) su ciascuno dei record nella tabella individualmente. Se avessi una clausola WHERE nell'istruzione UPDATE, solo i record specifici verrebbero bloccati in scrittura e, di nuovo, se la clausola WHERE selezionasse un intervallo, avresti un intervallo bloccato.

Qualsiasi record che avesse un blocco di lettura dal precedente SELECT verrebbe automaticamente elevato a un blocco di scrittura.

Un blocco in scrittura impedisce ad altre query di ottenere un blocco in lettura o in scrittura.

Puoi usare Innotop per vederlo eseguendolo in modalità Blocco, avviare una transazione, eseguire la query (ma non eseguirla) e vedrai i blocchi in Innotop. Inoltre, puoi visualizzare i dettagli senza Innotop con SHOW ENGINE INNODB STATUS .

Blocchi di stallo

La tua query è vulnerabile a un deadlock se due istanze sono state eseguite contemporaneamente. Se la query A ha i blocchi di lettura, quindi la query B ha i blocchi di lettura, la query A dovrebbe attendere il rilascio dei blocchi di lettura della query B prima di poter acquisire i blocchi di scrittura. Tuttavia, la query B non rilascerà i blocchi di lettura fino al termine e non verrà completata a meno che non possa acquisire blocchi di scrittura. La query A e la query B sono in una situazione di stallo e, di conseguenza, in una situazione di stallo.

Pertanto, potresti voler eseguire un blocco tabella esplicito, sia per evitare l'enorme quantità di blocchi di record (che utilizzano memoria e influiscono sulle prestazioni), sia per evitare un deadlock.

Un approccio alternativo consiste nell'usare SELECT ... FOR UPDATE sul tuo SELECT interno. Questo inizia con i blocchi di scrittura su tutte le righe invece di iniziare con la lettura e l'escalation.

Tabelle derivate

Per il SELECT interno, MySQL crea una tabella temporanea derivata. Una tabella derivata è una copia effettiva non indicizzata dei dati che risiedono nella tabella temporanea creata automaticamente da MySQL (al contrario di una tabella temporanea che crei in modo esplicito e alla quale puoi aggiungere indici).

Poiché MySQL utilizza una tabella derivata, questo è il vecchio valore temporaneo a cui fai riferimento nella tua domanda. In altre parole, non c'è magia qui. MySQL lo fa proprio come lo faresti altrove, con un valore temporaneo.

Puoi vedere la tabella derivata eseguendo un EXPLAIN rispetto alla tua istruzione UPDATE (supportata in MySQL 5.6+).