Dove memorizza i dati di transazione di InnoDB prima di eseguirne il commit?


12

Ho fatto alcuni test usando READ_COMMITTEDe READ_UNCOMMITTEDa casa, usando la tecnologia JDBC.

Vedo che READ_UNCOMMITTEDpuò effettivamente leggere dati non impegnati, ad esempio dati da alcune transazioni non ancora impegnate (potrebbe eseguire una query UPDATE).

Domande

  • Dove vengono archiviati i dati non impegnati, in modo tale che una READ_UNCOMMITTEDtransazione possa leggere i dati non impegnati da un'altra transazione?
  • Perché non è possibile per una READ_COMMITTEDtransazione leggere dati non impegnati, ovvero eseguire una "lettura sporca"? Quale meccanismo applica questa limitazione?

Risposte:


11

" Dove vengono archiviati i dati non impegnati, in modo tale che una transazione READ_UNCOMMITTED possa leggere i dati non impegnati da un'altra transazione? "

Le nuove versioni dei record non impegnati (cluster PK) vengono trattate come la versione "corrente" del record sulla pagina. Quindi possono essere memorizzati nel pool di buffer e / o nel tablespace (ad esempio tablename.ibd). Le transazioni che devono quindi creare un'istantanea / vista in qualcosa di diverso da READ-UNCOMMITTED, devono costruire una versione precedente della riga (seguendo l'elenco cronologico) utilizzando i record UNDO (memorizzati nel tablespace di sistema ). Durante la lettura del record senza commit, InnoDB potrebbe anche aver bisogno di leggere alcuni record di indice secondario senza commit dal buffer di modifica e applicarli prima di presentare nuovamente il record all'utente.

È questo comportamento che può rendere i rollback in InnoDB relativamente costosi. È il grande fattore che può anche portare a potenziali problemi di prestazioni derivanti da transazioni inattive di lunga durata che contengono record aggiornati, poiché tali transazioni bloccheranno le operazioni di eliminazione e l'elenco cronologico delle vecchie versioni dei record aumenta e i record UNDO necessari per ricostruire quelle vecchie versioni su richiesta, continuerà a crescere. Rallenta le nuove transazioni che devono leggere una versione precedente / impegnata del record, in quanto devono attraversare un elenco cronologico sempre più lungo - che è un elenco singolarmente collegato di record UNDO - e fare più lavoro per ricostruire la vecchia versione del record. Quindi finisci per usare molti cicli della CPU (per non parlare delle primitive di blocco interne: mutex, rw_locks, semafori, ecc.

Spero che abbia senso? :)

In quanto FYI, in MySQL 5.7 è possibile spostare il tablespace UNDO e disconnettersi dal tablespace di sistema e farli troncare automaticamente. Possono diventare piuttosto grandi se si dispone di una transazione a esecuzione prolungata che impedisce le operazioni di eliminazione, determinando una lunghezza dell'elenco cronologico molto lunga e in continua crescita. La loro memorizzazione nel tablespace di sistema era la causa più comune di un file ibdata1 enorme / in crescita, che a sua volta non può essere troncato / ridotto / svuotato per recuperare successivamente quello spazio.


4

Hai chiesto

dove vengono archiviati i dati non impegnati, in modo che una transazione READ_UNCOMMITTED possa leggere i dati non impegnati da un'altra transazione?

Per rispondere alla tua domanda, devi sapere come appare l'architettura InnoDB.

L'immagine seguente è stata creata anni fa dal CTO di Percona Vadim Tkachenko

Architettura di InnoDB

Secondo la documentazione MySQL sul modello di transazione e sul blocco di InnoDB

Un COMMIT significa che le modifiche apportate alla transazione corrente vengono rese permanenti e diventano visibili ad altre sessioni. Un'istruzione ROLLBACK, invece, annulla tutte le modifiche apportate dalla transazione corrente. Sia COMMIT che ROLLBACK rilasciano tutti i blocchi InnoDB impostati durante la transazione corrente.

Poiché COMMIT e ROLLBACK regolano la visibilità dei dati, READ COMMITTED e READ UNCOMMITTED dovrebbero fare affidamento su strutture e meccanismi che registrano le modifiche

  1. Segmenti di rollback / Annulla spazio
  2. Ripeti registri
  3. Blocchi vuoti contro i tavoli coinvolti

I segmenti di rollback e Annulla spazio saprebbero come apparivano i dati modificati prima dell'applicazione delle modifiche. Ripeti registri saprebbe quali modifiche devono essere portate in avanti per visualizzare i dati aggiornati.

Hai anche chiesto

perché non è possibile per una transazione READ_COMMITTED leggere dati non impegnati, ovvero eseguire una "lettura sporca"? Quale meccanismo applica questa limitazione?

Entrano in gioco i file Ripristina registri, Annulla spazio e Bloccato. Devi anche considerare il pool di buffer InnoDB (dove puoi misurare le pagine sporche con innodb_max_dirty_pages_pct , innodb_buffer_pool_pages_dirty e innodb_buffer_pool_bytes_dirty ).

Alla luce di ciò, READ COMMITTED saprebbe quali dati appaiono permanentemente. Pertanto, non è necessario cercare pagine sporche non impegnate. LEGGI IMPEGNATO non sarebbe altro che una lettura sporca che è stata commessa. LEGGI UNCOMMITTED avrebbe continuato a sapere quali righe devono essere bloccate e quali registri di ripetizione devono essere letti o ignorati per rendere visibili i dati.

Per comprendere appieno il blocco delle righe per la gestione dell'isolamento, leggi Il modello di transazione e il blocco di InnoDB


1
Innanzitutto, grazie per la risposta e la modifica del mio post ... Quindi, prima di un COMMIT, le modifiche non sono visibili agli altri utenti del sistema? Qui l'utente significa letteralmente una transazione, giusto? Dal momento che READ UNCOMMITTED è in grado di leggere dati senza commit, dove vengono letti questi dati da questo livello di isolamento? Potrebbe esserci più di una fonte di dati non impegnati per un particolare elemento di dati in un database? In tal caso, quali dati non impegnati verranno quindi letti?
Shuzheng,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.