Un modo per selezionare senza causare il blocco in MySQL?


126

Query:

SELECT COUNT(online.account_id) cnt from online;

Ma la tabella online viene anche modificata da un evento, quindi frequentemente posso vedere il blocco in esecuzione show processlist.

Esiste una grammatica in MySQL che può fare un'istruzione select che non causa blocchi?

E ho dimenticato di menzionare sopra che è su un database slave MySQL.

Dopo che l'ho aggiunto my.cnf:transaction-isolation = READ-UNCOMMITTED allo slave incontrerà un errore:

Errore "Registrazione binaria impossibile. Messaggio: Il livello di transazione 'READ-UNCOMMITTED' in InnoDB non è sicuro per la modalità binlog 'STATEMENT' 'su query

Quindi, esiste un modo compatibile per farlo?


3
Per gli altri che incontrano questa domanda e si trovano in difficoltà con i blocchi sui loro tavoli: come mySQL utilizza i blocchi internamente dipende dal motore di archiviazione. Leggi la risposta di @zombat di seguito.
Simon Forsberg,

Risposte:


169

Trovato un articolo intitolato "MYSQL WITH NOLOCK"

https://web.archive.org/web/20100814144042/http://sqldba.org/articles/22-mysql-with-nolock.aspx

in MS SQL Server devi fare quanto segue:

SELECT * FROM TABLE_NAME WITH (nolock)

e l'equivalente MYSQL è

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ;

MODIFICARE

Michael Mior ha suggerito quanto segue (dai commenti)

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
COMMIT ;

54
Solo una nota per i futuri lettori che potresti voler eliminare SESSIONe quindi il livello di transazione si applica solo alla transazione successiva. Quindi, sostituisci semplicemente la terza istruzione sopra con COMMIT. Questo sarà un noop in questo caso, ma avrà un effetto collaterale di terminare la transazione e ripristinare il livello di isolamento predefinito.
Michael Mior,

3
Solo una nota, quel link è morto ... :(
longda

5
Siamo spiacenti, ma devo sottovalutare questa risposta per non aver menzionato qui le differenze molto importanti tra InnoDB e MyISAM. Come affermato da @omg sopra, questo funzionerà per InnoDB ma non per le tabelle MyISAM.
Simon Forsberg,

4
@Craig È certamente inesatto che MyISAM non stia emettendo blocchi READ durante le query SELECT - ci sono blocchi e in opposizione a InnoDB quei blocchi sono blocchi di tabella, bloccando tutti i blocchi WRITE richiesti e tutte le successive query durante l'esecuzione. La domanda originale sembra riguardare InnoDB, sebbene i livelli di isolamento siano inesistenti anche per MyISAM: i documenti per loSET TRANSACTION stato dell'istruzione : "Questa istruzione imposta il livello di isolamento della transazione, utilizzato per le operazioni sulle tabelle InnoDB".
syneticon-dj,

1
Punto concesso. :-) Stavo davvero cercando di fare riferimento al comportamento di blocco di MyISAM vs InnoDB. Queste soluzioni basate sul livello di isolamento non si applicano a MyISAM, che non è transazionale, quindi utilizza un semplice blocco della tabella. MyISAM UPDATE e DELETE devono attendere che il blocco della tabella venga cancellato, quindi qualsiasi successiva SELECT in coda dietro la richiesta di scrittura, viene bloccata fino al termine della scrittura. MyISAM non ha "letture sporche" e non c'è modo di consentire che la maggior parte delle scritture avvenga contemporaneamente alle letture, quindi non ha senso aggrapparsi ai commenti qui "non riuscendo a rivolgersi a MyISAM". Penso che sia quello a cui stavo arrivando. :-)
Craig

24

Se la tabella è InnoDB, vedere http://dev.mysql.com/doc/refman/5.1/en/innodb-consistent-read.html - utilizza la lettura coerente (modalità senza blocco) per i SELECT "che fanno non specificare FOR UPDATE o LOCK IN SHARE MODE se l'opzione innodb_locks_unsafe_for_binlog è impostata e il livello di isolamento della transazione non è impostato su SERIALIZZABILE. Pertanto, nessun blocco viene impostato sulle righe lette dalla tabella selezionata ".


16

Uso

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED.

I documenti versione 5.0 sono qui .

I documenti versione 5.1 sono qui .


2
Grazie, penso che sia vicino, ma per quanto tempo avrà effetto questa affermazione? Userò questa affermazione in un programma PHP, e dovrebbe essere ripristinato al meglio LIVELLO DI ISOLAMENTO DELLE TRANSAZIONI una volta terminata la query
omg

14

Potresti voler leggere questa pagina del manuale di MySQL. Il modo in cui una tabella viene bloccata dipende dal tipo di tabella che è.

MyISAM utilizza i blocchi di tabella per ottenere una velocità di lettura molto elevata, ma se si dispone di un'istruzione UPDATE in attesa, i SELECTS futuri verranno messi in coda dietro all'aggiornamento.

Le tabelle di InnoDB utilizzano il blocco a livello di riga e non avrai il blocco dell'intera tabella dietro un AGGIORNAMENTO. Esistono altri tipi di problemi di blocco associati a InnoDB, ma potresti trovarlo adatto alle tue esigenze.


1
"IMPOSTA IL LIVELLO DI ISOLAMENTO DELLE TRANSAZIONI LEGGI UNCOMMITTED" funzionerà per le tabelle MyISAM?
omg,

5
Le tabelle MyISAM non supportano le transazioni in alcun modo. Una query transazionale verrà eseguita su una tabella MyISAM, quindi verrà eseguita la query menzionata sopra, ma non ha alcun effetto.
Zombat,

1
Quindi cosa posso fare per evitare SELECTS in coda nel caso di MyISAM?
omg,

6
cosa posso fare per evitare che SELECTS faccia la fila nel caso di MyISAM? Passa a innodb. MyISAM utilizza blocchi a livello di tabella per ogni query. Questo è il principale difetto.
Frank Farmer,

2

A seconda del tipo di tabella, il blocco funzionerà diversamente, ma anche un conteggio SELECT. Per le tabelle MyISAM un semplice conteggio SELECT (*) DA non deve bloccare la tabella poiché accede ai metadati per estrarre il conteggio dei record. Innodb richiederà più tempo poiché deve acquisire la tabella in un'istantanea per contare i record, ma non dovrebbe causare il blocco.

Dovresti avere almeno concurrent_insert impostato su 1 (impostazione predefinita). Quindi, se non ci sono "spazi" nel file di dati da riempire per la tabella, gli inserimenti verranno aggiunti al file e SELECT e INSERT possono avvenire contemporaneamente con le tabelle MyISAM. Si noti che l'eliminazione di un record pone un "gap" nel file di dati che tenterà di essere riempito con inserimenti e aggiornamenti futuri.

Se elimini raramente i record, puoi impostare concurrent_insert uguale a 2 e gli inserti verranno sempre aggiunti alla fine del file di dati. Quindi le selezioni e gli inserimenti possono avvenire contemporaneamente, ma il tuo file di dati non sarà mai più piccolo, indipendentemente dal numero di record che elimini (tranne tutti i record).

La linea di fondo, se hai molti aggiornamenti, inserisce e seleziona su una tabella, dovresti renderlo InnoDB. Tuttavia, puoi mescolare liberamente i tipi di tabella in un sistema.


1

un altro modo per abilitare la lettura sporca in mysql è aggiungere un suggerimento: BLOCCO IN MODALITÀ CONDIVIDI

SELECT * FROM TABLE_NAME LOCK IN SHARE MODE; 

"Se autocommit è impostato su 1, le clausole LOCK IN SHARE MODE e FOR UPDATE non hanno effetto." ... e autocommit = 1 è predefinito
Martin Zvarík il

0

Da questo riferimento:

Se si acquisisce esplicitamente un blocco tabella con LOCK TABLES, è possibile richiedere un blocco READ LOCAL anziché un blocco READ per consentire ad altre sessioni di eseguire inserimenti simultanei mentre la tabella è bloccata.


0

Le SELECT normalmente non eseguono alcun blocco che ti interessa sulle tabelle InnoDB. Il livello di isolamento delle transazioni predefinito indica che le selezioni non bloccano gli elementi.

Naturalmente la contesa accade ancora.


1
So che questo post è vecchio, ma questa risposta è troppo generale ed è solo a volte vera. Vedi dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html . I blocchi sono sicuramente acquisiti per le letture, a seconda del livello di isolamento. Nello specifico, in questo caso, il poster ha a che fare con database replicati e ha dichiarato esplicitamente che può usare show processlistper vedere effettivamente i blocchi. Quindi è lecito ritenere che ci siano effettivamente dei blocchi.
Craig,

1
La risposta è sempre vera Esistono ovviamente dei blocchi: alcuni mutex interni all'interno di innodb che vengono utilizzati (ad esempio mutex del pool buffer innodb). La maggior parte degli utenti non si preoccupa o nota di questi blocchi e normalmente si contendono solo durante le operazioni DDL (ad esempio se si dispone di un pool buffer 16G e si esegue "drop table" in un altro thread). Ma non richiede alcun blocco di riga per impostazione predefinita. Ecco cosa intendevo. La risposta è stata piuttosto vaga però.
MarkR

1
Sempre sempre? Cosa succede se il livello di isolamento della transazione è impostato su serializzabile o se l'istruzione select utilizza LOCK IN SHARE MODE e autocommit è disabilitato? So che molti server di database (quasi tutti?) Ora utilizzano l'isolamento dello snapshot per impostazione predefinita anziché la vera serializzazione, ma non ci sono ancora giustificazioni occasionali per forzare letture serializzabili? Ma sembra che tu stia dicendo che in tutti i casi remotamente normali, le condizioni predefinite in MySQL non causano blocchi di lettura che interessano altri thread, quindi non preoccuparti di un problema che non hai? Ho provato a annullare il mio downvote, BTW. Mi dispiace ...
Craig

3
Ho detto "normalmente". Volevo dire se fai una selezione normale (senza FOR UPDATE o LOCK IN SHARE MODE) e usi il livello di isolamento della transazione predefinito. Ci sono alcuni casi validi per cambiare il livello di isolamento, ma lo farei solo su base per sessione, mai di default.
Mark R
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.