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

Wydajność MySQL podczas aktualizacji wiersza za pomocą FK

Rozważ następujący schemat:(Pozostały pozostałe instrukcje dla Twojej wygody) :

-- drop table if exists spies;
create table spies
(   id int primary key,
    weapon_id int not null,
    name varchar(100) not null,
    key(weapon_id),
    foreign key (weapon_id) references weapons(id)
)engine=InnoDB;

-- drop table if exists weapons;
create table weapons
(   id int primary key,
    name varchar(100) not null
)engine=InnoDB;

insert weapons(id,name) values (1,'slingshot'),(2,'Ruger');
insert spies(id,weapon_id,name) values (1,2,'Sally');
-- truncate table spies;

Teraz mamy 2 procesy, P1 i P2. Najlepiej przetestować, gdzie P1 to być może MySQL Workbench, a P2 to okno wiersza poleceń MySql. Innymi słowy, musisz ustawić to jako osobne połączenia i dobrze. Musiałbyś mieć skrupulatne oko, aby krok po kroku przeprowadzać je we właściwy sposób (opisany w Narracji poniżej) i zobacz jego wpływ na inne okno procesu.

Rozważ następujące zapytania, pamiętając, że zapytanie mysql, które nie jest opakowane w jawną transakcję, samo w sobie jest transakcją niejawną. Ale poniżej zwróciłem się na wyraźne:

P1:

START TRANSACTION;
-- place1
UPDATE spies SET name = 'Bond', weapon_id = 1 WHERE id = 1;
-- place2
COMMIT;

P2:

START TRANSACTION;
-- place1
UPDATE spies SET name = 'Bond' WHERE id = 1;
-- place2
COMMIT;

P3:

START TRANSACTION;
-- place1
SELECT id into @mine_to_use from weapons where id=1 FOR UPDATE; -- place2
-- place3
COMMIT;

P4:

START TRANSACTION;
-- place1
SELECT id into @mine_to_use from spies where id=1 FOR UPDATE; -- place2
-- place3
COMMIT;

Q5 (mieszanka pytań):

SELECT * from weapons;
SELECT * from spies;

Narracja

P1: Kiedy zaczyna się P1 Q1 , i dostaje się na miejsce2, uzyskał wyłączną blokadę aktualizacji na poziomie rzędu w obu tabelach broni i szpiegów dla rzędu id=1 (łącznie 2 rzędy, 1 rząd w każdym stole). Można to udowodnić, gdy P2 zaczyna biegać w Q3, dociera do miejsca 1, ale blokuje się na miejscu 2 i zostaje zwolniony dopiero, gdy P1 zbliża się do wywołania COMMIT. Wszystko, co właśnie powiedziałem o P2 uruchamiającym Q3, dotyczy tego samego w przypadku P2 uruchamiającego Q4. Podsumowując, na ekranie P2 miejsce 2 zawiesza się do momentu zatwierdzenia P1.

Jeszcze raz uwaga o transakcjach niejawnych. Twoje prawdziwe Zapytanie Q1 wykona to bardzo szybko, a wyjście z niego spowoduje niejawne zatwierdzenie. Jednak poprzedni akapit wyjaśnia to, gdy masz uruchomione bardziej czasochłonne procedury.

Q2: Kiedy zaczyna się P1 Q2 , i dostaje się na miejsce2, uzyskał wyłączną blokadę aktualizacji na poziomie rzędu w obu tabelach broni i szpiegów dla rzędu id=1 (łącznie 2 rzędy, 1 rząd w każdym stole). Jednak P2 nie ma problemów z blokowaniem weapons w trzecim kwartale , ale P2 ma problemy z blokowaniem w Q4 w miejscu2 spies .

Tak więc różnice między Q1 i Q2 sprowadzają się do tego, że MySQL wie, że indeks FK nie jest związany z kolumną w UPDATE, a instrukcja stwierdza, że ​​w Note1 poniżej.

Gdy P1 uruchamia Q1, P2 nie ma problemów z zapytaniami typu Q5 bez blokady tylko do odczytu. Jedynymi problemami są to, jakie wersje danych widzi P2 na podstawie obowiązującego POZIOMU ​​IZOLACJI.

Uwaga1 :Ze strony podręcznika MySQL zatytułowanej Blokady ustawione według różnych Instrukcje SQL w InnoDB :

Powyższe jest powodem zachowania Q2: jest taki, że P2 może wykonać UPDATE lub uzyskać wyłączną chwilową blokadę UPDATE na weapons . Dzieje się tak, ponieważ silnik nie wykonuje UPDATE z P1 na weapon_id i dlatego nie ma blokady na poziomie wiersza w tej tabeli.

Aby sprowadzić to z powrotem do 50 000 stóp, największym zmartwieniem jest czas, w którym blokada jest utrzymywana albo w transakcji niejawnej (bez START/COMMIT), albo w transakcji jawnej przed COMMIT. Procesowi równorzędnemu można teoretycznie zabronić nabywania potrzeby UPDATE w nieskończoność. Ale każda próba uzyskania tej blokady jest zarządzana przez jej ustawienie dla innodb_lock_wait_timeout . Oznacza to, że domyślnie wygasa po około 60 sekundach. Aby zobaczyć swoje ustawienie, uruchom:

select @@innodb_lock_wait_timeout;

Dla mnie w tej chwili jest to 50 (sekund).



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Optymalizacja importu MySQL (konwertowanie pełnego zrzutu SQL do szybkiego / użyj rozszerzonych wstawek)

  2. Łącznik MySQL dla Pythona

  3. jak zmienić nazwę schematu w MySQL?

  4. Błąd #1241 - Operand powinien zawierać 1 kolumnę w Mysql

  5. MySql — sposób na aktualizację fragmentu ciągu?