Her er mine noter fra arbejdet med MySQL-support på et nyligt, mærkeligt låseproblem (version 5.1.37):
Alle rækker og indeksposter, der krydses for at komme til de rækker, der ændres, vil blive låst. Det er dækket på:
http://dev.mysql.com/doc /refman/5.1/da/innodb-locks-set.html
"En låsende læsning, en UPDATE eller en DELETE sætter generelt postlåse på hver indekspost, der scannes i behandlingen af SQL-sætningen. Det er ligegyldigt, om der er WHERE-betingelser i sætningen, der ville udelukke rækken. Det gør InnoDB husker ikke den nøjagtige WHERE-tilstand, men ved kun hvilke indeksområder der blev scannet ... Hvis du ikke har nogen indekser, der passer til dit udsagn, og MySQL skal scanne hele tabellen for at behandle udsagnet, bliver hver række i tabellen låst, hvilket i slå blokerer alle indsættelser af andre brugere til bordet."
Det er. En løsning, der ofte er nyttig, er at gøre:
OPDATERING, hvilken som helst, der er angivet til noget, hvor primærnøgle er (vælg primærnøgle fra hvilken, hvor begrænsninger rækkefølge efter primærnøgle);
Det indre udvalg behøver ikke at tage låse, og opdateringen vil så have mindre arbejde at gøre for opdateringen. Order by-klausulen sikrer, at opdateringen udføres i primær nøglerækkefølge, så den matcher InnoDBs fysiske rækkefølge, den hurtigste måde at gøre det på.
Hvor et stort antal rækker er involveret, som i dit tilfælde, kan det være bedre at gemme det valgte resultat i en midlertidig tabel med tilføjet en flagkolonne. Vælg derefter fra den midlertidige tabel, hvor flaget ikke er sat til at få hver batch. Kør opdateringer med en grænse på f.eks. 1000 eller 10000, og sæt flaget for batchen efter opdateringen. Grænserne vil holde mængden af låsning på et acceptabelt niveau, mens det valgte arbejde kun skal udføres én gang. Forpligt dig efter hver batch for at frigøre låsene.
Du kan også fremskynde dette arbejde ved at lave en udvalgt sum af en uindekseret kolonne, før du udfører hver batch af opdateringer. Dette vil indlæse datasiderne i bufferpuljen uden at tage låse. Så vil låsningen vare i et kortere tidsrum, fordi der ikke vil være nogen diskaflæsninger.
Dette er ikke altid praktisk, men når det er det, kan det være meget nyttigt. Hvis du ikke kan gøre det i batches, kan du i det mindste prøve at vælge først for at forudindlæse dataene, hvis de er små nok til at passe ind i bufferpuljen.
Hvis det er muligt, skal du bruge READ COMMITTED-transaktionsisoleringstilstanden. Se:
http://dev.mysql.com/doc/refman /5.1/da/set-transaction.html
For at få den reducerede låsning kræves brug af rækkebaseret binær logning (i stedet for standardsætningsbaseret binær logning).
To kendte problemer:
-
Underforespørgsler kan nogle gange være mindre end ideelt optimeret. I dette tilfælde var det en uønsket afhængig underforespørgsel - det forslag, jeg kom med om at bruge en underforespørgsel, viste sig derfor at være uhensigtsmæssigt sammenlignet med alternativet i dette tilfælde.
-
Sletninger og opdateringer har ikke det samme udvalg af forespørgselsplaner som udvalgte udsagn, så nogle gange er det svært at optimere dem ordentligt uden at måle resultaterne for at finde ud af præcis, hvad de laver.
Begge disse er gradvist i bedring. Denne fejl er et eksempel, hvor vi netop har forbedret de tilgængelige optimeringer for en opdatering, selvom ændringerne er betydelige, og den stadig gennemgår kvalitetskontrol for at være sikker på, at den ikke har nogen store negative virkninger:
http://bugs.mysql.com/bug.php?id=36569