2009-05-27 20 views
107

Query:Un modo per selezionare senza causare il blocco in MySQL?

SELECT COUNT(online.account_id) cnt from online; 

Ma tavolo online viene modificata anche da un evento, così spesso posso vedere blocco eseguendo show processlist.

C'è qualche grammatica in MySQL che può rendere l'istruzione select che non causa blocchi?

e ho dimenticato di menzionare sopra che è su un database MySQL schiava.

Dopo ho aggiunto nella my.cnf:transaction-isolation = READ-UNCOMMITTED lo schiavo si incontreranno con l'errore:

Error 'Binary logging not possible. Message: Transaction level 'READ-UNCOMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT'' on query 

Quindi, c'è un modo compatibile per fare questo?

+2

Per gli altri che incontrano questa domanda e hanno difficoltà con i blocchi sulle loro tabelle: Come mySQL utilizza i blocchi internamente dipende dal motore di archiviazione. Leggi la risposta di @zombat qui sotto. –

risposta

11

Si consiglia di leggere this page del manuale MySQL. Il modo in cui una tabella viene bloccata dipende dal tipo di tabella.

MyISAM utilizza blocchi di tabella di raggiungere una velocità molto elevata di lettura, ma se avete un attesa un'istruzione UPDATE, quindi seleziona i futuri sarà in coda dietro l'aggiornamento.

tabelle InnoDB utilizzare il blocco a livello di riga, e non avrete l'intera tabella lock-up dietro un aggiornamento. Esistono altri tipi di problemi di blocco associati a InnoDB, ma potresti trovarlo adatto alle tue esigenze.

+1

Il lavoro di "IMPOSTAZIONE LIVELLO DI ISOLAMENTO LETTURA NON CORRETTO" funziona per le tabelle MyISAM? – omg

+5

Le tabelle MyISAM non supportano transazioni in nessuna forma. Una query transazionale verrà eseguita su una tabella MyISAM, quindi la query che hai citato sopra verrà eseguita, ma non ha alcun effetto. – zombat

+1

Quindi cosa posso fare per evitare l'accodamento SELECTS nel caso di MyISAM? – omg

0

Da this di riferimento:

If you acquire a table lock explicitly with LOCK TABLES, you can request a READ LOCAL lock rather than a READ lock to enable other sessions to perform concurrent inserts while you have the table locked.

19

Se la tabella è InnoDB, vedere http://dev.mysql.com/doc/refman/5.1/en/innodb-consistent-read.html - usa (no-bloccaggio modalità) coerente lettura obbligata per SELECT "che non specificano FOR UPDATE o bloccare in modalità di condivisione se l'opzione innodb_locks_unsafe_for_binlog è impostata e il livello di isolamento della transazione non è impostato su SERIALIZABLE, quindi non vengono impostati blocchi sulle righe lette dalla tabella selezionata ".

13

Usa

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED.

versione 5.0 Docs sono here.

versione 5.1 Docs sono here.

+2

Grazie, penso che sia vicino, ma quanto durerà questa affermazione? Utilizzerò questa istruzione in un programma PHP e dovrei essere il migliore ripristinare LIVELLO DI ISOLAMENTO DELLA TRANSAZIONE automaticamente una volta terminata la query – omg

2

A seconda del tipo di tabella, il blocco verrà eseguito in modo diverso, ma lo sarà anche un conteggio SELECT. Per le tabelle MyISAM, una semplice tabella SELECT count (*) FROM non deve bloccare la tabella poiché accede ai metadati per ottenere il conteggio dei record. Innodb impiegherà più tempo poiché deve catturare la tabella in un'istantanea per contare i record, ma non dovrebbe causare il blocco.

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

Se raramente eliminare i record, quindi è possibile impostare concurrent_insert uguale a 2, e gli inserti sarà sempre aggiunto alla fine del file di dati. Quindi selezioni e inserimenti possono avvenire simultaneamente, 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 disponi di molti aggiornamenti, inserti e selezioni su una tabella, dovresti renderla InnoDB. Puoi comunque mescolare liberamente i tipi di tabella in un sistema.

130

Trovato un articolo intitolato "MySQL con NOLOCK"

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

in MSSQL si dovrebbe effettuare le seguenti operazioni:

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 ; 

EDIT

Michael Mior suggerito le seguenti (dai commenti)

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

Grazie, quindi questo funzionerà per Innodb, ma cosa succede se MyISAM? – omg

+41

Solo una nota per i futuri lettori che si potrebbe desiderare di eliminare 'SESSIONE' e quindi il livello di transazione si applica solo alla transazione successiva. Quindi, sostituisci semplicemente la terza dichiarazione sopra con 'COMMIT'. In questo caso, questo sarà un noop, ma avrà un effetto collaterale di terminare la transazione e reimpostare il livello di isolamento predefinito. –

+3

Solo una nota, quel collegamento è morto ... :( – longda

1

SELECT normalmente non fanno alcun blocco che vi preoccupate sulle tabelle InnoDB. Il livello di isolamento della transazione predefinito significa che seleziona non bloccare le cose.

Naturalmente la contesa si verifica ancora.

+0

So che questo post è vecchio, ma questa risposta è troppo generica e solo a volte è vera. Vedi http://dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html. Le serrature sono sicuramente acquisite per le letture, a seconda del livello di isolamento. Nello specifico, in questo caso, il poster si occupa di database replicati e afferma esplicitamente che può usare 'show processlist' per vedere effettivamente i blocchi. Quindi è lecito ritenere che in realtà ci siano blocchi bloccati. – Craig

+1

La risposta è sempre vera. C'è, naturalmente, un certo lock - alcuni mutex interni all'interno di innodb che vengono usati (mutex del pool di buffer innodb, per esempio). La maggior parte degli utenti non si preoccupa né nota questi blocchi e di solito si limitano a sostenere le operazioni DDL (ad esempio se si dispone di un pool di buffer 16G e si esegue "drop table" in un altro thread). Ma per impostazione predefinita non richiede alcun blocco di riga. Ecco cosa intendevo. La risposta è stata abbastanza vaga però. – MarkR

+1

_ Sempre_ sempre? Cosa succede se il livello di isolamento della transazione è impostato su serializzabile, oppure l'istruzione select utilizza LOCK IN SHARE MODE e l'autocommit è disabilitato? So che molti (più/tutti?) Server di database ora usano l'isolamento dello snapshot per impostazione predefinita invece della serializzazione vera, ma non ci sono ancora giustificazioni occasionali per forzare letture serializzabili? Ma sembra che tu stavi dicendo che in tutti i casi remotamente normali, le condizioni predefinite in MySQL non causano blocchi di lettura che influenzano altri thread, quindi non preoccuparti di un problema che non hai? Ho provato a annullare il mio downvote, BTW. Scusa ... – Craig

0

un altro modo per abilitare la lettura dirty in mysql è aggiungere un suggerimento: LOCK IN SHARE MODE SELECT * FROM TABLE_NAME LOCK IN SHARE MODE;

Problemi correlati