sql >> Database >  >> RDS >> Sqlserver

SQL Deadlock-vraag

SELECT's kunnen niet in een impasse raken met andere SELECT, omdat ze alleen gedeelde vergrendelingen verkrijgen. U zegt dat we moeten bedenken dat deze SELECT's nu 'exclusieve leesvergrendelingen vereisen', maar dit is voor ons niet mogelijk omdat 1) er niet zoiets bestaat als een exlusive read lock en 2) reads krijgen geen exclusieve locks.

Maar je stelt wel een meer algemene vraag, of simpele uitspraken kunnen vastlopen. Het antwoord is een duidelijk, volmondig JA . Sloten worden verkregen bij uitvoering, niet vooraf geanalyseerd en gesorteerd en vervolgens in een bepaalde volgorde verworven. Het zou voor de engine onmogelijk zijn om vooraf de benodigde vergrendelingen te kennen, omdat deze afhankelijk zijn van de feitelijke gegevens op de schijf, en om de gegevens te lezen die de engine nodig heeft om ... de gegevens te vergrendelen.

Deadlocks tussen eenvoudige statements (SELECt vs. UPDATE of SELECT vs. DELETE) als gevolg van een verschillende indextoegangsvolgorde komen vrij vaak voor en zijn zeer eenvoudig te onderzoeken, diagnosticeren en oplossen. Maar let op:er is altijd een schrijfbewerking betrokken, omdat lezen elkaar niet kunnen blokkeren. Voor deze discussie moet het toevoegen van een UPDLOCK- of XLOCK-hint aan een SELECT worden beschouwd als schrijven. Je hebt niet eens een JOIN nodig, een secundaire index kan het probleem van de toegangsvolgorde introduceren dat tot een impasse leidt, zie Lees/Schrijf Deadlock .

En tot slot, het schrijven van SELECT FROM A JOIN B of schrijven SELECT FROM B JOIN A is totaal niet relevant. De query-optimizer is vrij om de toegangsvolgorde naar eigen goeddunken te herschikken, de eigenlijke tekst van de query legt op geen enkele manier de volgorde van uitvoering op.

Bijgewerkt

Ik ben bang dat er geen recept voor een koekjesvorm is. De oplossing zal van geval tot geval afhangen. Uiteindelijk zijn impasses in database-applicaties een feit van het leven. Ik begrijp dat dit misschien absurd klinkt, zoals in 'we zijn op de maan geland, maar we kunnen geen correcte database-applicatie schrijven', maar er zijn sterke factoren in het spel die vrijwel garanderen dat applicaties uiteindelijk op een impasse zullen stuiten. Gelukkige impasses zijn de gemakkelijkst om met fouten om te gaan, eenvoudig de status opnieuw lezen, de logica toepassen, de nieuwe status opnieuw schrijven. Dat gezegd hebbende, er zijn enkele goede praktijken die de frequentie van impasses drastisch kunnen verminderen, tot het punt waarop ze bijna zijn verdwenen:

  • Probeer een consistent toegangspatroon te hebben voor Schrijven . Zorg voor duidelijk gedefinieerde regels met zaken als 'een transactie wordt altijd in deze volgorde weergegeven:Customers -> OrderHeaders -> OrderLines .' Merk op dat de bestelling moet worden opgevolgd binnen een transactie . Kortom, rangschik alle tabellen in uw schema en specificeert u dat alle updates in rangorde moeten plaatsvinden. Dit komt uiteindelijk neer op codediscipline van de individuele bijdrager die de code schrijft, omdat hij ervoor moet zorgen dat hij de update in de juiste volgorde schrijft binnen een transactie.
  • Verkort de duur van schrijft. De gebruikelijke wijsheid luidt als volgt:voer aan het begin van de transactie alle leesbewerkingen uit (lees de bestaande status), verwerk vervolgens de logica en bereken nieuwe waarden, en schrijf vervolgens alle updates aan het einde van de transactie. Vermijd een patroon als 'read->write->logic->read->write', maar doe 'read->read->logic->write->write'. Natuurlijk bestaat het echte vakmanschap uit hoe om te gaan met actuele, echte, individuele gevallen waarin men blijkbaar moet moet doen schrijft halverwege de transactie. Een speciale opmerking moet hier worden gemaakt over een specifiek type transactie:transacties die worden aangedreven door een wachtrij, die per definitie hun activiteit beginnen door uit de wachtrij te komen (=schrijven). Deze applicaties waren altijd notoir moeilijk te schrijven en gevoelig voor fouten (vooral deadlocks), gelukkig zijn er manieren om dit te doen, zie Tabellen gebruiken als wachtrijen .
  • Verminder het aantal leesbewerkingen. Tabelscans zijn de meest voorkomende oorzaak van impasses. Een juiste indexering zal niet alleen de impasses elimineren, maar kan ook de prestaties in het proces verbeteren.
  • Snapshot-isolatie . Dit komt het dichtst in de buurt van een gratis lunch om impasses te vermijden. Ik heb het opzettelijk als laatste geplaatst, omdat het kan maskeren andere problemen (zoals onjuiste indexering) in plaats van ze op te lossen.

Proberen dit probleem op te lossen met een LockCustomerByXXX aanpak werkt helaas niet. Pessimistische vergrendeling schaalt niet. Optimistische gelijktijdigheid updates zijn de goed te doen als je fatsoenlijke prestaties wilt hebben.



  1. hoe CLOB-gegevens over te dragen van de ene database naar een andere externe ORACLE-database met DBLinks

  2. Mysql haalt alle rijen met limiet op

  3. Kunnen we DDL-opdrachten gebruiken in een voorbereide verklaring (PostgreSQL)?

  4. Meerdere max()-waarden selecteren met een enkele SQL-instructie