sql >> Databasteknik >  >> RDS >> Mysql

Dummies guide till att låsa in innodb

Här är mina anteckningar från att arbeta med MySQL-stöd på ett nyligen märkligt låsningsproblem (version 5.1.37):

Alla rader och indexposter som passeras för att komma till raderna som ändras kommer att låsas. Det finns på:

http://dev.mysql.com/doc /refman/5.1/en/innodb-locks-set.html

"En låsande läsning, en UPPDATERING eller en DELETE sätter vanligtvis postlås på varje indexpost som skannas i bearbetningen av SQL-satsen. Det spelar ingen roll om det finns WHERE-villkor i satsen som skulle utesluta raden. InnoDB gör det. kommer inte ihåg det exakta WHERE-villkoret, men vet bara vilka indexintervall som skannades. ... Om du inte har några index som är lämpliga för din sats och MySQL måste skanna hela tabellen för att bearbeta satsen, blir varje rad i tabellen låst, vilket i vänd blockerar alla inlägg av andra användare till bordet."

Det är. En lösning som ofta är till hjälp är att göra:

UPPDATERA vilken som helst ställ in vad som helst till något där primärnyckeln är (välj primärnyckel från vilken ändringsbar där begränsningar ordnar efter primärnyckel);

Det inre urvalet behöver inte ta lås och uppdateringen kommer då att ha mindre arbete att göra för uppdateringen. Order by-klausulen säkerställer att uppdateringen görs i primärnyckelordning för att matcha InnoDB:s fysiska ordning, det snabbaste sättet att göra det.

Där ett stort antal rader är inblandade, som i ditt fall, kan det vara bättre att lagra det valda resultatet i en tillfällig tabell med en flaggkolumn tillagd. Välj sedan från den tillfälliga tabellen där flaggan inte är inställd för att få varje batch. Kör uppdateringar med en gräns på säg 1000 eller 10000 och ställ in flaggan för batchen efter uppdateringen. Gränserna kommer att hålla mängden låsning på en acceptabel nivå medan det valda arbetet bara behöver göras en gång. Beslut efter varje batch för att frigöra låsen.

Du kan också påskynda detta arbete genom att göra en utvald summa av en oindexerad kolumn innan du gör varje batch av uppdateringar. Detta kommer att ladda datasidorna i buffertpoolen utan att låsa. Då kommer låsningen att pågå under en kortare tidsperiod eftersom det inte blir några diskavläsningar.

Detta är inte alltid praktiskt men när det är det kan det vara till stor hjälp. Om du inte kan göra det i omgångar kan du åtminstone prova att välja först för att ladda data i förväg, om den är tillräckligt liten för att passa in i buffertpoolen.

Använd om möjligt läget READ COMMITTED transaktionsisolering. Se:

http://dev.mysql.com/doc/refman /5.1/sv/set-transaction.html

För att få den minskade låsningen krävs användning av radbaserad binär loggning (istället för standardsatsbaserad binär loggning).

Två kända problem:

  1. Undersökningar kan ibland vara mindre än idealiskt optimerade. I det här fallet var det en oönskad beroende underfråga - förslaget jag gjorde att använda en underfråga visade sig vara olämpligt jämfört med alternativet i det här fallet på grund av det.

  2. Borttagningar och uppdateringar har inte samma utbud av frågeplaner som utvalda uttalanden så ibland är det svårt att optimera dem ordentligt utan att mäta resultaten för att komma fram till exakt vad de gör.

Båda dessa förbättras gradvis. Den här buggen är ett exempel där vi just har förbättrat de tillgängliga optimeringarna för en uppdatering, även om ändringarna är betydande och den fortfarande går igenom kvalitetskontroll för att vara säker på att den inte har några stora negativa effekter:

http://bugs.mysql.com/bug.php?id=36569




  1. Välj endast unik rad/post i mysql

  2. Hur räknar man hur många läkare som är bokade av varje patient?

  3. Hitta liknande strängar med PostgreSQL snabbt

  4. Homebrew MySQL 8.0.18 på macOS 10.15 Catalina kommer inte att köras som tjänst