Le query di AGGIORNAMENTO delle precedenti due domande ( Domanda 1 , Domanda 2 ) stanno colpendo la tabella "persone" con PRIMARY KEY con blocco a livello di riga. Questo è ciò che ho affermato nella domanda 1 del 6 giugno 2011 alle 10:03
Tutte le transazioni attraversano la chiave PRIMARY. Poiché PRIMARY è un indice cluster in InnoDB, la chiave PRIMARY e la riga stessa sono insieme. Quindi, attraversare una riga e il PRIMARY KEY sono la stessa cosa. Pertanto, qualsiasi blocco dell'indice sul PRIMARY KEY è anche un blocco a livello di riga.
Qualcos'altro non è stato ancora considerato che può attribuire lentezza agli indici: l'uso di indici NON UNICI in InnoDB. Ogni ricerca indicizzata in InnoDB che utilizza indici non univoci ha anche l'ID riga di ogni riga collegata alla chiave non univoca. Il rowID emana sostanzialmente dall'indice cluster . L'aggiornamento di indici non univoci DEVE SEMPRE interagire con l'indice cluster ANCHE SE LA TABELLA NON HA UN TASTO PRIMARIO.
Un'altra cosa a cui pensare è il processo di gestione dei nodi BTREE in un indice. A volte, richiede la divisione della pagina dei nodi. Tutte le voci nel nodo BTREE di indici non univoci contengono campi non univoci PIÙ il rowID all'interno dell'indice cluster. Per mitigare correttamente la divisione di tali pagine BTREE senza disturbare l'integrità dei dati, la riga associata all'ID riga deve presentare un blocco a livello di riga internamente.
Se la tabella "persone" ha molti indici non univoci, preparati ad avere un gran numero di pagine indice nel tablespace, oltre ad avere piccoli blocchi di piccole file che ti si intrufolano di tanto in tanto.
C'è un altro fattore che non è così ovvio: la popolazione chiave
A volte, quando un indice viene popolato, i valori chiave che compongono gli indici potrebbero diventare sbilenco nel tempo e causare il passaggio da MySQL Query Optimizer a ricerche con chiave, a scansioni di indici e infine a scansioni di tabelle complete. Che non è possibile controllare se non si riprogetta la tabella con nuovi indici per compensare le chiavi di sbilenco ot.Fornisci la struttura della tabella per la tabella "persone", il conteggio della tabella "persone" e l'output degli indici di visualizzazione per la tabella "persone" .
Anche se le query utilizzano solo il PRIMARY KEY, la sbilenco delle chiavi negli indici non univoci richiede comunque il bilanciamento BTREE e la suddivisione della pagina. Tale gestione BTREE produrrà un notevole rallentamento a causa di blocchi intermittenti a livello di riga che non si prevede di accadere.
AGGIORNAMENTO 2011-06-14 22:19
Domande dalla domanda 1
UPDATE people SET company_id = 1610, name = '<name>', password = '<hash>',
temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@yahoo.com',
phone = NULL, mobile = '<phone>', iphone_device_id = 'android:<id>-<id>',
iphone_device_time = '2011-06-06 05:35:09', last_checkin = '2011-06-06 05:24:42',
location_lat = <lat>, location_long = -<lng>, gps_strength = 3296,
picture_blob_id = 1190,
authority = 1, active = 1, date_created = '2011-04-13 20:21:20',
last_login = '2011-06-06 05:35:09', panic_mode = 0,
battery_level = NULL, battery_state = NULL WHERE people_id = 3125
UPDATE people SET company_id = 1610, name = '<name>', password = '<hash>',
temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@yahoo.com',
phone = NULL, mobile = '<phone>', iphone_device_id = 'android:<id>-<id>-<id>-<id>',
iphone_device_time = '2011-06-06 05:24:42', last_checkin = '2011-06-06 05:35:07',
location_lat = <lat>, location_long = -<lng>, gps_strength = 3296,
picture_blob_id = 1190,
authority = 1, active = 1, date_created = '2011-04-13 20:21:20',
last_login = '2011-06-06 05:35:09', panic_mode = 0,
battery_level = NULL, battery_state = NULL WHERE people_id = 3125
Immagina la sequenza negli eventi
- Trova la riga tramite PRIMARY KEY
- Blocca la riga e l'indice cluster
- Crea dati MVCC per tutte le colonne da aggiornare
- Quattro colonne sono indicizzate (email, company_id, iphone_device_id, picture_blob_id)
- Ogni indice richiede la gestione BTREE
- All'interno dello stesso spazio di transazione, i passaggi 1-5 stanno tentando di essere ripetuti sulla stessa riga, aggiornando le stesse colonne (invia lo stesso messaggio di posta elettronica in entrambe le query, company_id è lo stesso in entrambe le query, picture_blob_id è lo stesso in entrambe le query, iphone_device_id diverso)
Domande dalla domanda 2
UPDATE people SET iphone_device_id=NULL
WHERE iphone_device_id='iphone:<device_id_blah>' AND people_id<>666;
UPDATE people SET company_id = 444, name = 'Dad', password = '<pass>',
temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@gmail.com',
phone = NULL, mobile = NULL, iphone_device_id = 'iphone:<device_id_blah>',
iphone_device_time = '2011-06-06 19:12:29', last_checkin = '2011-06-07 02:49:47',
location_lat = <lat>, location_long = <lng>, gps_strength = 66,
picture_blob_id = 1661,
authority = 1, active = 1, date_created = '2011-03-20 19:18:34',
last_login = '2011-06-07 11:15:01', panic_mode = 0, battery_level = 0.55,
battery_state = 'unplugged' WHERE people_id = 666;
Queste due query sono ancora più confuse perché la prima query aggiorna tutto tranne people_id 666. Centinaia di righe sono dolorosamente bloccate solo con la prima query. La seconda query sta aggiornando people_id 666 eseguendo la sequenza di 5 eventi. La prima query esegue quelle stesse 5 sequenze di eventi su ogni riga coinvolta tranne people_id 666 ma l'indice per iphone_device_id si trova su un percorso interecept con due query diverse. Qualcuno deve bloccare le pagine BTREE in base all'ordine di arrivo.
Di fronte a queste due coppie di query su un percorso di collisione, eventualmente bloccare le stesse pagine BTREE all'interno di un indice può essere un'esperienza sconvolgente per InnoDB o qualsiasi RDBMS conforme ACID. Pertanto, un rallentamento dell'indice è il destino di queste coppie di query a meno che non sia possibile garantire che le query vengano eseguite con AUTOCOMMIT = 1 o consentendo letture sporche (anche se collisioni come queste rendono READ-COMMITTED e READ-UNCOMMITED un incubo per MVCC).
AGGIORNAMENTO 2011-06-15 10:29
@RedBlueThing: nelle query della domanda 2, la prima query è una query a intervallo, quindi vengono raggiunti molti blocchi di riga. Si noti inoltre che entrambe le query stanno tentando di bloccare lo stesso spazio ID pagina 0 n. 4611 n bit 152 è bloccato in PRIMARY KEY, noto anche come indice cluster.
Per assicurarti che l'app sia almeno in esecuzione in base alla serie di eventi previsti, ci sono due diverse opzioni che potresti provare:
Opzione 1) Convertire questa tabella in MyISAM (almeno su un server di sviluppo). Ogni UPDATE, INSERT e DELETE imporranno un blocco completo della tabella in base all'ordine di arrivo.
Opzione 2) Provare a utilizzare il livello di isolamento SERIALIZZABILE . Ciò bloccherà tutte le righe previste in modalità CONDIVISO.
La sequenza di eventi previsti si interromperà o avrà esito positivo utilizzando queste due opzioni alternative. Se entrambe queste opzioni falliscono, dovrai guardare l'app e dare priorità all'ordine di esecuzione delle tue query. Una volta stabilita quella priorità, puoi semplicemente annullare queste opzioni (per l'opzione 1, torna a InnoDB, per l'opzione 2, torna al livello di isolamento predefinito [smetti di usare SERIALIZABLE]).