Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Błąd zakleszczenia MySQL

Po przeczytaniu trochę więcej odkryłem, że ponieważ InnoDB używa blokowania na poziomie wiersza, zakleszczenia mogą wystąpić podczas wstawiania lub aktualizowania pojedynczego wiersza, ponieważ akcje nie są atomowe. Biegłem:

SHOW ENGINE INNODB STATUS

znaleźć informacje na temat ostatniego impasu. Znalazłem:

------------------------
LATEST DETECTED DEADLOCK
------------------------
140106 17:22:41
*** (1) TRANSACTION:
TRANSACTION 63EB5222A, ACTIVE 0 sec starting index read
mysql tables in use 3, locked 3
LOCK WAIT 9 lock struct(s), heap size 3112, 6 row lock(s), undo log entries 2
MySQL thread id 4304350, OS thread handle 0x7fd3b74d3700, query id 173460207 192.168.0.2 sharecash Updating
UPDATE `click_rollups` SET `clicks` = `clicks` + 1, `last_updated` = '1389046961' WHERE `camp_id` = '27739' AND `country` = 'US' AND `clicks` < '1000' AND `time_created` = '1389046866'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 186 page no 407 n bits 1272 index `country` of table `sharecash`.`click_rollups` trx id 63EB5222A lock_mode X waiting
*** (2) TRANSACTION:
TRANSACTION 63EB52225, ACTIVE 0 sec fetching rows
mysql tables in use 3, locked 3
177 lock struct(s), heap size 31160, 17786 row lock(s), undo log entries 2
MySQL thread id 4304349, OS thread handle 0x7fd6961c8700, query id 173460194 192.168.0.1 sharecash Updating
UPDATE `click_rollups` SET `clicks` = `clicks` + 1, `last_updated` = '1389046961' WHERE `camp_id` = '30949' AND `country` = 'US' AND `clicks` < '1000' AND `time_created` = '1388964767'
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 186 page no 407 n bits 1272 index `country` of table `sharecash`.`click_rollups` trx id 63EB52225 lock_mode X
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 186 page no 512 n bits 384 index `PRIMARY` of table `sharecash`.`click_rollups` trx id 63EB52225 lock_mode X locks rec but not gap waiting
*** WE ROLL BACK TRANSACTION (1)

Widać, że dwa zapytania, które powodują zakleszczenie, są w rzeczywistości dokładnie tymi samymi zapytaniami. Pokazuje, że w klauzuli WHERE są też różne parametry dla kolumn, więc rzeczywiste wiersze, które są blokowane, są różne, co wydawało mi się nieco sprzeczne z intuicją - jak operacje na różnych zestawach wierszy mogą spowodować zakleszczenie?

Odpowiedź wydaje się być taka, że ​​impas wynika z blokowania wpisów silnika zapytań w strukturach indeksowania. Jeśli spojrzysz na powyższe dane wyjściowe, zobaczysz, że jedna transakcja ma blokadę w określonej części określonej strony w country indeksu i wymaga blokady na części indeksu klucza podstawowego, podczas gdy druga transakcja jest zasadniczo odwrotna.

Niezmiennikiem w tej części naszej aplikacji jest to, że tylko jeden wiersz miałby mniej niż 1000 kliknięć, więc wierzę, że poprzez naprawienie tego problemu problem zakleszczenia zostanie zminimalizowany, ponieważ będzie ogólnie mniej blokowanych. Dokumentacja MySQL sugeruje kodowanie aplikacji, aby zawsze ponownie wystawiać transakcje w przypadku wycofania z powodu zakleszczenia, co zapobiegłoby temu problemowi powodującemu błędy stron. Jeśli jednak ktoś ma inne pomysły, jak faktycznie uniknąć tych impasów, ponownie, opublikuj je w komentarzach!

EDYTUJ -

country indeks nie musiał być używany przez transakcję, jak dla każdego camp_id wartość była tylko garstka (zwykle tylko 1) różnych wartości country , z których każdy odpowiadał tylko jednemu wierszowi. Dodałem wskazówkę dotyczącą indeksu do zapytania, aby przestało używać tego indeksu, a problem został rozwiązany bez żadnego spadku wydajności (prawdopodobnie niewielki zysk).




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak sprawdzić, które e-maile znajdują się na tych samych listach?

  2. Czas przechowywania MySQL - typ danych?

  3. Jak zaokrąglić liczby w bazie danych do dwóch miejsc po przecinku za pomocą zapytania MySql

  4. Jakiego typu kolumny używa SQLAlchemy dla tekstu w MySQL?

  5. Czy powinienem używać PDO PARAM_LOB lub PARAM_STR dla typu MySQL TEXT?