Jakikolwiek sposób na wybranie bez powodowania blokowania w MySQL?

126

Pytanie:

SELECT COUNT(online.account_id) cnt from online;

Ale tabela online jest również modyfikowana przez zdarzenie, więc często widzę blokadę, uruchamiając show processlist.

Czy jest jakaś gramatyka w MySQL, która może spowodować, że instrukcja select nie spowoduje blokad?

I zapomniałem wspomnieć powyżej, że znajduje się on w podrzędnej bazie danych MySQL.

Po dodaniu do my.cnf:transaction-isolation = READ-UNCOMMITTED slave'a spotkam się z błędem:

Błąd „Rejestracja binarna nie jest możliwa. Komunikat: Poziom transakcji „READ-UNCOMMITTED” w InnoDB nie jest bezpieczny w trybie binlog „STATEMENT” w zapytaniu

Czy jest więc zgodny sposób na zrobienie tego?

o mój Boże
źródło
3
Dla innych, którzy napotykają to pytanie i mają trudności z blokadami na swoich tabelach: To, w jaki sposób mySQL używa wewnętrznych blokad, zależy od silnika pamięci masowej. Przeczytaj odpowiedź @zombat poniżej.
Simon Forsberg

Odpowiedzi:

169

Znaleziono artykuł zatytułowany „MYSQL WITH NOLOCK”

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

w MS SQL Server wykonasz następujące czynności:

SELECT * FROM TABLE_NAME WITH (nolock)

a odpowiednikiem MYSQL jest

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

EDYTOWAĆ

Michael Mior zasugerował co następuje (z komentarzy)

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
COMMIT ;
Jon Erickson
źródło
54
Tylko uwaga dla przyszłych czytelników, którą możesz zechcieć wyeliminować, aby SESSIONpoziom transakcji obowiązywał tylko dla następnej transakcji. Następnie po prostu zamień trzecią instrukcję powyżej na COMMIT. W tym przypadku będzie to noop, ale będzie miało efekt uboczny zakończenia transakcji i zresetowania do domyślnego poziomu izolacji.
Michael Mior
3
Tylko uwaga, ten link nie działa ... :(
longda,
5
Przepraszam, ale muszę negatywnie ocenić tę odpowiedź, ponieważ nie wspominam tutaj o bardzo ważnych różnicach między InnoDB i MyISAM. Jak stwierdzono powyżej @omg, będzie to działać dla InnoDB, ale nie dla tabel MyISAM.
Simon Forsberg,
4
@Craig Z pewnością niedokładne jest to, że MyISAM nie wydaje blokad READ podczas zapytań SELECT - blokady i w przeciwieństwie do InnoDB te blokady są blokadami tabel, blokując wszystkie żądane blokady WRITE i wszystkie kolejne zapytania podczas wykonywania. Wydaje się, że pierwotne pytanie dotyczyło InnoDB, a poziomy odseparowania nie istnieją również w przypadku MyISAM - dokumentacja zawieraSET TRANSACTION stan instrukcji : „Ta instrukcja określa poziom izolacji transakcji, używany do operacji na tabelach InnoDB”.
syneticon-dj
1
Point przyznał. :-) Naprawdę próbowałem odnieść się do zachowania blokującego MyISAM vs InnoDB. Te rozwiązania oparte poziom izolacji nie stosuje się do MyISAM, który nie jest transakcyjny, więc używa się prostego blokada tabeli. MyISAM UPDATE i DELETE muszą czekać, aż blokada tabeli zostanie wyczyszczona, więc każda kolejna kolejka SELECT znajduje się za żądaniem zapisu, blokowana do zakończenia zapisu. MyISAM nie ma „brudnych odczytów” i nie ma sposobu, aby większość zapisów odbywała się równolegle z odczytami, więc nie ma sensu narzekać na jakiekolwiek komentarze, które „nie odnoszą się do MyISAM”. Myślę, że właśnie do tego zmierzałem. :-)
Craig
24

Jeśli tabela to InnoDB, zobacz http://dev.mysql.com/doc/refman/5.1/en/innodb-consistent-read.html - używa spójnego odczytu (tryb bez blokowania) dla WYBORÓW „, które to robią nie określaj FOR UPDATE lub LOCK IN SHARE MODE, jeśli opcja innodb_locks_unsafe_for_binlog jest ustawiona, a poziom odseparowania transakcji nie jest ustawiony na SERIALIZABLE. W związku z tym żadne blokady nie są ustawiane w wierszach odczytywanych z wybranej tabeli ".

Alex Martelli
źródło
16

Posługiwać się

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED.

Dokumenty w wersji 5.0 są tutaj .

Dokumenty w wersji 5.1 są tutaj .

Nie ja
źródło
2
Dziękuję, myślę, że już blisko, ale jak długo to stwierdzenie będzie miało wpływ? Zamierzam użyć tej instrukcji w programie PHP i najlepiej zresetować POZIOM IZOLACJI TRANSAKCJI automatycznie po zakończeniu zapytania
omg
14

Możesz przeczytać tę stronę podręcznika MySQL. Sposób blokowania tabeli zależy od typu tabeli.

MyISAM używa blokad tabel, aby osiągnąć bardzo dużą prędkość odczytu, ale jeśli masz oczekującą instrukcję UPDATE, to przyszłe SELECTS ustawią się w kolejce za UPDATE.

Tabele InnoDB używają blokowania na poziomie wierszy i nie będziesz mieć całej tabeli zablokowanej za UPDATE. Z InnoDB wiąże się inny rodzaj problemów z blokowaniem, ale może się okazać, że odpowiada on Twoim potrzebom.

zombat
źródło
1
Czy „USTAW POZIOM IZOLACJI TRANSAKCJI ODCZYT NIEZGODZONY” będzie działać dla tabel MyISAM?
omg
5
Tabele MyISAM nie obsługują transakcji w żadnej formie. Zapytanie transakcyjne zostanie uruchomione na tabeli MyISAM, więc zapytanie, o którym wspomniałeś powyżej, zostanie wykonane, ale nie odniesie skutku.
zombat
1
Co zatem mogę zrobić, aby w przypadku MyISAM uniknąć kolejkowania SELECTS?
omg
6
co mogę zrobić, aby w przypadku MyISAM uniknąć kolejkowania SELECTS? Przejdź do innodb. MyISAM używa blokad na poziomie tabeli dla każdego zapytania. To jest główna wada.
Frank Farmer
2

W zależności od typu stołu, blokowanie będzie działać inaczej, ale liczy się też SELECT. W przypadku tabel MyISAM prosta tabela SELECT count (*) FROM nie powinna blokować tabeli, ponieważ uzyskuje dostęp do metadanych w celu pobrania liczby rekordów. Innodb zajmie więcej czasu, ponieważ musi złapać tabelę w migawce, aby policzyć rekordy, ale nie powinno powodować blokowania.

Powinieneś przynajmniej ustawić concurrent_insert na 1 (domyślnie). Następnie, jeśli w pliku danych nie ma "luk" do wypełnienia tabeli, do pliku zostaną dołączone wstawki, a operacje SELECT i INSERT mogą być wykonywane jednocześnie z tabelami MyISAM. Należy zauważyć, że usunięcie rekordu powoduje powstanie „luki” w pliku danych, która będzie próbowała wypełnić przyszłe wstawienia i aktualizacje.

Jeśli rzadko usuwasz rekordy, możesz ustawić wartość concurrent_insert na 2, a wstawienia będą zawsze dodawane na końcu pliku danych. Następnie zaznaczenia i wstawienia mogą odbywać się jednocześnie, ale plik danych nigdy nie będzie mniejszy, bez względu na to, ile rekordów usuniesz (z wyjątkiem wszystkich rekordów).

Podsumowując, jeśli masz dużo aktualizacji, wstawek i selekcji w tabeli, powinieneś uczynić to InnoDB. Możesz jednak dowolnie mieszać typy tabel w systemie.

Brent Baisley
źródło
1

Innym sposobem włączenia brudnego odczytu w mysql jest dodanie wskazówki: LOCK IN SHARE MODE

SELECT * FROM TABLE_NAME LOCK IN SHARE MODE; 
PuGong
źródło
„Jeśli autocommit jest ustawiona na 1, klauzule LOCK IN SHARE MODE i FOR UPDATE nie działają”. ... i autocommit = 1 jest domyślne
Martin Zvarík
0

Z tego odniesienia:

Jeśli uzyskasz blokadę tabeli jawnie za pomocą LOCK TABLES, możesz zażądać blokady READ LOCAL zamiast blokady READ, aby umożliwić innym sesjom wykonywanie współbieżnych operacji wstawiania, gdy tabela jest zablokowana.

Paul Sonier
źródło
0

SELECT zwykle nie blokują tabel InnoDB, na których Ci zależy. Domyślny poziom izolacji transakcji oznacza, że ​​wybory nie blokują rzeczy.

Oczywiście nadal dochodzi do sporów.

MarkR
źródło
1
Wiem, że ten post jest stary, ale ta odpowiedź jest zbyt ogólna i tylko czasami jest prawdziwa. Zobacz dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html . Blokady na pewno nabyte czyta, w zależności od poziomu izolacji. Konkretnie w tym przypadku, plakat dotyczy replikowanych baz danych i wyraźnie stwierdził, że może użyć, show processlistaby faktycznie zobaczyć zamki. Można więc bezpiecznie założyć, że w rzeczywistości są otwierane zamki.
Craig,
1
Odpowiedź jest zawsze prawdziwa. Jest oczywiście pewne blokowanie - niektóre wewnętrzne muteksy wewnątrz innodb, które są używane (na przykład muteks puli buforów innodb). Większość użytkowników nie przejmuje się tymi blokadami ani nie zauważa tych blokad i zwykle walczą tylko podczas operacji DDL (na przykład jeśli masz pulę buforów 16G i „upuszczasz tabelę” w innym wątku). Ale domyślnie nie przyjmuje żadnych blokad wierszy. O to mi chodziło. Odpowiedź była jednak dość niejasna.
MarkR
1
Zawsze ? Co się stanie, jeśli poziom izolacji transakcji jest ustawiony na serializowalny lub instrukcja select używa LOCK IN SHARE MODE, a automatyczne zatwierdzanie jest wyłączone? Wiem, że wiele (większość / wszystkie?) Serwerów baz danych używa teraz domyślnie izolacji migawek zamiast prawdziwej serializacji, ale czy nadal nie ma sporadycznych uzasadnień wymuszania odczytów możliwych do serializacji? Ale brzmi to tak, jakbyś mówił, że we wszystkich zdalnie normalnych przypadkach domyślne warunki w MySQL nie powodują blokad odczytu, które mają wpływ na inne wątki, więc nie martw się o problem, którego nie masz? Przy okazji, próbowałem cofnąć swój głos przeciw. Przepraszam ...
Craig
3
Powiedziałem „normalnie nie”. Chodziło mi o to, że jeśli wykonasz normalny wybór (bez AKTUALIZACJI lub BLOKADY W TRYBIE UDZIAŁU) i użyjesz domyślnego poziomu izolacji transakcji. Istnieje kilka ważnych przypadków zmiany poziomu izolacji, ale zrobiłbym to tylko na podstawie sesji, nigdy domyślnie.
MarkR