sql >> Database >  >> RDS >> Mysql

MySQL-prestaties bij het updaten van rij met FK

Overweeg het volgende schema:(Remsts achtergelaten voor uw gemak) :

-- 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;

Nu hebben we 2 processen, P1 en P2. Het beste om te testen waar P1 misschien MySQL Workbench is en P2 een MySql-opdrachtregelvenster is. Met andere woorden, je moet dit als aparte verbindingen en recht instellen. Je zou een nauwgezet oog moeten hebben om deze stap voor stap op de juiste manier uit te voeren (beschreven in het Verhaal hieronder) en zie de impact ervan op het andere procesvenster.

Overweeg de volgende vragen, waarbij u er rekening mee houdt dat een mysql-query die niet in een expliciete transactie is verpakt, zelf een impliciete transactie is. Maar hieronder zwaaide ik voor expliciet:

Q1:

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

Q2:

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

Q3:

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

Q4:

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

Q5 (een mengelmoes van vragen):

SELECT * from weapons;
SELECT * from spies;

Verhalend

Q1: Wanneer P1 begint Q1 , en komt op plaats2, het heeft een exclusieve updatevergrendeling op rijniveau verkregen in beide tafels, wapens en spionnen voor de id =1 rij (2 rijen in totaal, 1 rij in elke tafel). Dit kan worden bewezen door P2 die Q3 begint uit te voeren, naar plaats 1 gaat, maar blokkeert op plaats 2 en pas wordt vrijgelaten wanneer P1 COMMIT begint te bellen. Alles wat ik net zei over P2 die Q3 draait, is idem voor P2 die Q4 draait. Samengevat, op het P2-scherm bevriest place2 totdat de P1 Commit.

Nog een opmerking over impliciete transacties. Je echte Q1-query gaat dit zeer snel uitvoeren en eruit komen zal een impliciete commit doen. In de vorige paragraaf wordt het echter opgesplitst als u meer tijdrovende routines zou moeten uitvoeren.

Q2: Wanneer P1 begint Q2 , en komt op plaats2, het heeft een exclusieve updatevergrendeling op rijniveau verkregen in beide tafels, wapens en spionnen voor de id =1 rij (2 rijen in totaal, 1 rij in elke tafel). P2 heeft echter geen problemen met Q3 die weapons blokkeert , maar P2 heeft blokkeringsproblemen met Q4 op place2 spies .

Dus de verschillen tussen Q1 en Q2 komen neer op MySQL, wetende dat de FK-index niet relevant is voor een kolom in de UPDATE, en de handleiding stelt dat in Opmerking1 hieronder.

Wanneer P1 Q1 uitvoert, heeft P2 geen problemen met het verkrijgen van Q5-query's met alleen-lezen zonder vergrendeling. De enige problemen zijn wat gegevensweergaven P2 ziet op basis van het aanwezige ISOLATIENIVEAU.

Opmerking1 :Van de MySQL-handleidingpagina getiteld Sloten ingesteld door Different SQL-statements in InnoDB :

Het bovenstaande is waarom het gedrag van Q2: is zodanig dat P2 vrij is om een ​​UPDATE uit te voeren of een UPDATE exclusieve tijdelijke vergrendeling op weapons te verkrijgen . Dit komt omdat de engine geen UPDATE uitvoert met P1 op wapen_id en dus geen vergrendeling op rijniveau heeft in die tabel.

Om dit terug te brengen tot 50.000 voet, is iemands grootste zorg de duur waarop een slot wordt vastgehouden, hetzij in een impliciete transactie (een zonder START/COMMIT), of een expliciete transactie vóór een COMMIT. Een peer-proces kan in theorie voor onbepaalde tijd worden verboden om zijn behoefte aan een UPDATE te verwerven. Maar elke poging om dat slot te verkrijgen wordt bepaald door de instelling voor innodb_lock_wait_timeout . Wat dat betekent, is dat er standaard na ongeveer 60 seconden een time-out optreedt. Voer:

. uit om uw instelling te bekijken
select @@innodb_lock_wait_timeout;

Voor mij is het op dit moment 50 (seconden).



  1. Het vermijden van frequente oproepen naar dezelfde weergave binnen een Oracle-procedure

  2. TSQL PIVOT MEERDERE KOLOMMEN

  3. Een lopende telling toevoegen aan rijen in een 'reeks' van opeenvolgende dagen

  4. Hoe alle fouten van alle SSIS-pakketten in een oplossing te krijgen?