Deblocarea Postgres Lock Manager. Bruce Momjian

Transcrierea discursului lui Bruce Momjian din 2020 „Deblocarea managerului de blocare Postgres”.

Deblocarea Postgres Lock Manager. Bruce Momjian

(Notă: Toate interogările SQL din slide-uri pot fi obținute de la acest link: http://momjian.us/main/writings/pgsql/locking.sql)

Buna ziua! Este grozav să fiu din nou aici, în Rusia. Îmi pare rău că nu am putut veni anul trecut, dar anul acesta Ivan și cu mine avem planuri mari. Sper să fiu aici mult mai des. Îmi place să vin în Rusia. Voi vizita Tyumen, Tver. Sunt foarte bucuros că voi putea vizita aceste orașe.

Numele meu este Bruce Momjian. Lucrez la EnterpriseDB și lucrez cu Postgres de peste 23 de ani. Locuiesc în Philadelphia, SUA. Călătoresc aproximativ 90 de zile pe an. Și particip la aproximativ 40 de conferințe. Ale mele site web, care conține diapozitivele pe care vi le voi arăta acum. Prin urmare, după conferință le puteți descărca de pe site-ul meu personal. De asemenea, conține aproximativ 30 de prezentări. Există, de asemenea, videoclipuri și un număr mare de intrări pe blog, peste 500. Aceasta este o resursă destul de informativă. Și dacă ești interesat de acest material, atunci te invit să-l folosești.

Am fost profesor, profesor înainte de a începe să lucrez cu Postgres. Și sunt foarte bucuros că acum voi putea să vă spun ceea ce sunt pe cale să vă spun. Aceasta este una dintre cele mai interesante prezentări ale mele. Și această prezentare conține 110 diapozitive. Vom începe să vorbim cu lucruri simple, iar până la sfârșit raportul va deveni din ce în ce mai complex și va deveni destul de complex.

Deblocarea Postgres Lock Manager. Bruce Momjian

Aceasta este o conversație destul de neplăcută. Blocarea nu este subiectul cel mai popular. Vrem ca asta să dispară undeva. E ca și cum ai merge la dentist.

Deblocarea Postgres Lock Manager. Bruce Momjian

  1. Blocarea este o problemă pentru mulți oameni care lucrează în baze de date și au mai multe procese care rulează în același timp. Au nevoie de blocare. Adică, astăzi vă voi oferi cunoștințe de bază despre blocare.
  2. ID-urile tranzacției. Aceasta este o parte destul de plictisitoare a prezentării, dar trebuie să fie înțelese.
  3. În continuare vom vorbi despre tipurile de blocare. Aceasta este o parte destul de mecanică.
  4. Și mai jos vom da câteva exemple de blocare. Și va fi destul de greu de înțeles.

Deblocarea Postgres Lock Manager. Bruce Momjian

Să vorbim despre blocare.

Deblocarea Postgres Lock Manager. Bruce Momjian

Terminologia noastră este destul de complexă. Câți dintre voi știți de unde vine acest pasaj? Doi oameni. Acesta este dintr-un joc numit Colossal Cave Adventure. Era un joc pe computer bazat pe text în anii 80, cred. Acolo trebuia să intri într-o peșteră, într-un labirint, iar textul se schimba, dar conținutul era aproximativ același de fiecare dată. Așa îmi amintesc acest joc.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și aici vedem numele lacătelor care ne-au venit de la Oracle. Le folosim.

Deblocarea Postgres Lock Manager. Bruce Momjian

Aici vedem termeni care mă încurcă. De exemplu, SHARE UPDATE ECXLUSIVE. Următorul SHARE RAW ECXLUSIVE. Sincer să fiu, aceste nume nu sunt foarte clare. Vom încerca să le luăm în considerare mai detaliat. Unele conțin cuvântul „share”, care înseamnă a separa. Unele conțin cuvântul „exclusiv”. Unele conțin ambele cuvinte. Aș dori să încep cu cum funcționează aceste încuietori.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și cuvântul „acces” este, de asemenea, foarte important. Și cuvintele „rând” sunt un șir. Adică, distribuția accesului, distribuția rândurilor.

Deblocarea Postgres Lock Manager. Bruce Momjian

O altă problemă care trebuie înțeleasă în Postgres, pe care, din păcate, nu o voi putea acoperi în discursul meu, este MVCC. Am o prezentare separată pe acest subiect pe site-ul meu. Și dacă credeți că această prezentare este grea, probabil că MVCC este cel mai greu al meu. Și dacă ești interesat, îl poți urmări pe site. Puteți viziona videoclipul.

Deblocarea Postgres Lock Manager. Bruce Momjian

Un alt lucru pe care trebuie să-l înțelegem sunt ID-urile tranzacțiilor. Multe tranzacții nu pot funcționa fără identificatori unici. Și aici avem o explicație despre ce este o tranzacție. Postgres are două sisteme de numerotare a tranzacțiilor. Știu că aceasta nu este o soluție foarte frumoasă.

Deblocarea Postgres Lock Manager. Bruce Momjian

De asemenea, rețineți că diapozitivele vor fi destul de greu de înțeles, așa că ceea ce este evidențiat cu roșu este ceea ce trebuie să fiți atenți.

Deblocarea Postgres Lock Manager. Bruce Momjian

http://momjian.us/main/writings/pgsql/locking.sql

Să vedem. Numărul tranzacției este evidențiat cu roșu. Funcția SELECT pg_back este afișată aici. Îmi returnează tranzacția și ID-ul tranzacției.

Încă un lucru, dacă vă place această prezentare și doriți să o rulați în baza de date, atunci puteți accesa acest link în roz și puteți descărca SQL-ul pentru această prezentare. Și îl puteți rula pur și simplu în PSQL și întreaga prezentare va fi imediat pe ecran. Nu va conține flori, dar cel puțin o putem vedea.

Deblocarea Postgres Lock Manager. Bruce Momjian

În acest caz, vedem ID-ul tranzacției. Acesta este numărul pe care i-am atribuit-o. Și există un alt tip de ID tranzacție în Postgres, care se numește ID tranzacție virtuală

Și trebuie să înțelegem asta. Acest lucru este foarte important, altfel nu vom putea înțelege blocarea în Postgres.

Un ID de tranzacție virtuală este un ID de tranzacție care nu conține valori persistente. De exemplu, dacă rulez o comandă SELECT, atunci cel mai probabil nu voi schimba baza de date, nu voi bloca nimic. Deci, atunci când rulăm un simplu SELECT, nu dăm acelei tranzacții un ID persistent. Îi dăm doar un act de identitate virtual acolo.

Și acest lucru îmbunătățește performanța Postgres, îmbunătățește capabilitățile de curățare, astfel încât ID-ul tranzacției virtuale este format din două numere. Primul număr de dinaintea barei oblice este ID-ul backend-ului. Și în dreapta vedem doar un contor.

Deblocarea Postgres Lock Manager. Bruce Momjian

Prin urmare, dacă rulez o solicitare, se spune că ID-ul backend-ului este 2.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și dacă rulez o serie de astfel de tranzacții, atunci vedem că contorul crește de fiecare dată când rulez o interogare. De exemplu, când rulez interogarea 2/10, 2/11, 2/12 etc.

Deblocarea Postgres Lock Manager. Bruce Momjian

Rețineți că aici sunt două coloane. În stânga vedem ID-ul tranzacției virtuale – 2/12. Și în dreapta avem un ID de tranzacție permanent. Și acest câmp este gol. Și această tranzacție nu modifică baza de date. Deci nu îi dau un ID de tranzacție permanent.

Deblocarea Postgres Lock Manager. Bruce Momjian

De îndată ce rulez comanda de analiză ((ANALYZE)), aceeași interogare îmi oferă un ID de tranzacție permanent. Uite cum s-a schimbat asta pentru noi. Nu aveam acest ID înainte, dar acum îl am.

Deblocarea Postgres Lock Manager. Bruce Momjian

Deci, iată o altă cerere, o altă tranzacție. Numărul tranzacției virtuale este 2/13. Și dacă cer un ID de tranzacție persistent, atunci când rulez interogarea, îl voi primi.

Deblocarea Postgres Lock Manager. Bruce Momjian

Deci, încă o dată. Avem un ID de tranzacție virtual și un ID de tranzacție persistent. Doar înțelegeți acest punct pentru a înțelege comportamentul Postgres.

Deblocarea Postgres Lock Manager. Bruce Momjian

Trecem la a treia secțiune. Aici vom parcurge pur și simplu diferitele tipuri de încuietori din Postgres. Nu este foarte interesant. Ultima secțiune va fi mult mai interesantă. Dar trebuie să luăm în considerare lucrurile de bază, pentru că altfel nu vom înțelege ce se va întâmpla în continuare.

Vom parcurge această secțiune, ne vom uita la fiecare tip de blocare. Și vă voi arăta exemple despre cum sunt instalate, cum funcționează, vă voi arăta câteva interogări pe care le puteți utiliza pentru a vedea cum funcționează blocarea în Postgres.

Deblocarea Postgres Lock Manager. Bruce Momjian

Pentru a crea o interogare și a vedea ce se întâmplă în Postgres, trebuie să emitem interogarea în vizualizarea de sistem. În acest caz, pg_lock este evidențiat cu roșu. Pg_lock este un tabel de sistem care ne spune ce blocaje sunt utilizate în prezent în Postgres.

Cu toate acestea, îmi este foarte greu să vă arăt pg_lock de la sine, deoarece este destul de complex. Așa că am creat o vizualizare care arată pg_locks. Și, de asemenea, face ceva pentru mine care îmi permite să înțeleg mai bine. Adică exclude încuietorile mele, propria mea sesiune etc. Este doar SQL standard și vă permite să vă arătați mai bine ce se întâmplă.

Deblocarea Postgres Lock Manager. Bruce Momjian

O altă problemă este că această vedere este foarte largă, așa că trebuie să creez o a doua - lockview2.

Deblocarea Postgres Lock Manager. Bruce Momjian Și îmi arată mai multe coloane din tabel. Și încă una care îmi arată restul coloanelor. Acest lucru este destul de complex, așa că am încercat să îl prezint cât mai simplu posibil.

Deblocarea Postgres Lock Manager. Bruce Momjian

Așa că am creat un tabel numit Lockdemo. Și am creat o linie acolo. Acesta este tabelul nostru exemplu. Și vom crea secțiuni doar pentru a vă arăta exemple de încuietori.

Deblocarea Postgres Lock Manager. Bruce Momjian

Deci, un rând, o coloană. Primul tip de blocare se numește ACCESS SHARE. Aceasta este cea mai puțin restrictivă blocare. Aceasta înseamnă că practic nu intră în conflict cu alte încuietori.

Și dacă dorim să definim în mod explicit o blocare, rulăm comanda „lock table”. Și evident se va bloca, adică în modul ACCESS SHARE lansăm tabelul de blocare. Și dacă rulez PSQL în fundal, încep a doua sesiune din prima mea sesiune în acest fel. Adică ce voi face aici? Trec la o altă sesiune și îi spun „arată-mi lockview pentru această solicitare”. Și aici am AccessShareLock în acest tabel. Este exact ceea ce am cerut. Și spune că blocul a fost repartizat. Foarte simplu.

Deblocarea Postgres Lock Manager. Bruce Momjian

Mai mult, dacă ne uităm la a doua coloană, atunci nu există nimic acolo. Sunt goale.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și dacă rulez comanda „SELECT”, atunci aceasta este modalitatea implicită (explicită) de a solicita AccessShareLock. Așa că îmi eliberez tabelul și rulez interogarea, iar interogarea returnează mai multe rânduri. Și într-una dintre rânduri vedem AccessShareLock. Astfel, SELECT apelează AccessShareLock pe masă. Și nu intră în conflict cu practic nimic, deoarece este o blocare de nivel scăzut.

Deblocarea Postgres Lock Manager. Bruce Momjian

Ce se întâmplă dacă rulez un SELECT și am trei tabele diferite? Anterior rulam doar un tabel, acum rulez trei: pg_class, pg_namespace și pg_attribute.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și acum, când mă uit la interogare, văd 9 AccessShareLocks în trei tabele. De ce? Trei tabele sunt evidențiate cu albastru: pg_attribute, pg_class, pg_namespace. Dar puteți vedea, de asemenea, că toți indecșii care sunt definiți prin aceste tabele au și AccessShareLock.

Și aceasta este o blocare care practic nu intră în conflict cu ceilalți. Și tot ceea ce face este pur și simplu să ne împiedice să resetam tabelul în timp ce îl selectăm. Are sens. Adică, dacă selectăm un tabel, acesta dispare în acel moment, atunci acest lucru este greșit, deci AccessShare este o blocare de nivel scăzut care ne spune „nu lăsați acest tabel în timp ce lucrez”. În esență, asta e tot ce face ea.

Deblocarea Postgres Lock Manager. Bruce Momjian

ROW SHARE - Această blocare este puțin diferită.

Deblocarea Postgres Lock Manager. Bruce Momjian

Să luăm un exemplu. SELECT ROW SHARE metoda de blocare a fiecărui rând individual. În acest fel, nimeni nu le poate șterge sau schimba în timp ce le urmărim.

Deblocarea Postgres Lock Manager. Bruce MomjianDeci, ce face SHARE LOCK? Vedem că ID-ul tranzacției este 681 pentru SELECT. Și asta este interesant. Ce s-a intamplat aici? Prima dată când vedem numărul este în câmpul „Blocare”. Luăm ID-ul tranzacției și spune că îl blochează în modul exclusiv. Tot ce face este că spune că am un rând care este blocat tehnic undeva în tabel. Dar nu spune unde anume. Ne vom uita la asta mai în detaliu puțin mai târziu.

Deblocarea Postgres Lock Manager. Bruce Momjian

Aici spunem că încuietoarea este folosită de noi.

Deblocarea Postgres Lock Manager. Bruce Momjian

Deci, o blocare exclusivă spune în mod explicit că este exclusivă. Și, de asemenea, dacă ștergeți un rând din acest tabel, atunci asta se va întâmpla, după cum puteți vedea.

Deblocarea Postgres Lock Manager. Bruce Momjian

SHARE EXCLUSIVE este o blocare mai lungă.

Deblocarea Postgres Lock Manager. Bruce Momjian

Aceasta este comanda analizorului (ANALYZE) care va fi utilizată.

Deblocarea Postgres Lock Manager. Bruce Momjian

SHARE LOCK – puteți bloca în mod explicit în modul de partajare.

Deblocarea Postgres Lock Manager. Bruce Momjian

De asemenea, puteți crea un index unic. Și acolo puteți vedea SHARE LOCK, care face parte din ele. Și încuie masa și îi pune un SHARE LOCK.

În mod implicit, SHARE LOCK pe un tabel înseamnă că alte persoane pot citi tabelul, dar nimeni nu îl poate modifica. Și asta este exact ceea ce se întâmplă atunci când creați un index unic.

Dacă creez un index concomitent unic, atunci voi avea un alt tip de blocare, deoarece, după cum vă amintiți, utilizarea indicilor concomitent reduce cerința de blocare. Și dacă folosesc o blocare normală, un index normal, atunci voi împiedica scrierea în indexul tabelului în timp ce acesta este creat. Dacă folosesc un index concomitent, atunci trebuie să folosesc un alt tip de blocare.

Deblocarea Postgres Lock Manager. Bruce Momjian

SHARE ROW EXCLUSIVE – din nou poate fi setat explicit (explicit).

Deblocarea Postgres Lock Manager. Bruce Momjian

Sau putem crea o regulă, adică să luăm un caz specific în care va fi folosită.

Deblocarea Postgres Lock Manager. Bruce Momjian

Blocarea EXCLUSIVĂ înseamnă că nimeni altcineva nu poate schimba masa.

Deblocarea Postgres Lock Manager. Bruce Momjian

Aici vedem diferite tipuri de încuietori.

Deblocarea Postgres Lock Manager. Bruce Momjian

ACCESS EXCLUSIVE, de exemplu, este o comandă de blocare. De exemplu, dacă o faci CLUSTER table, atunci asta va însemna că nimeni nu va putea scrie acolo. Și blochează nu numai tabelul în sine, ci și indecșii.

Deblocarea Postgres Lock Manager. Bruce Momjian

Aceasta este a doua pagină a blocării ACCESS EXCLUSIVE, unde vedem exact ce blochează în tabel. Blocează rânduri individuale de masă, ceea ce este destul de interesant.

Acestea sunt toate informațiile de bază pe care am vrut să le dau. Am vorbit despre încuietori, despre ID-uri de tranzacție, am vorbit despre ID-uri de tranzacție virtuale, despre ID-uri permanente de tranzacție.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și acum vom trece prin câteva exemple de blocare. Aceasta este partea cea mai interesantă. Vom analiza cazuri foarte interesante. Și scopul meu în această prezentare este să vă ofer o mai bună înțelegere a ceea ce face de fapt Postgres atunci când încearcă să blocheze anumite lucruri. Cred că se pricepe foarte bine la blocarea pieselor.

Să ne uităm la câteva exemple concrete.

Deblocarea Postgres Lock Manager. Bruce Momjian

Vom începe cu tabele și un rând într-un tabel. Când introduc ceva, am ExclusiveLock, ID tranzacție și ExclusiveLock afișate pe tabel.

Deblocarea Postgres Lock Manager. Bruce Momjian

Ce se întâmplă dacă mai introduc două rânduri? Și acum tabelul nostru are trei rânduri. Și am inserat un rând și am primit asta ca rezultat. Și dacă mai introduc două rânduri, ce e ciudat în asta? Este un lucru ciudat aici pentru că am adăugat trei rânduri la acest tabel, dar încă mai am două rânduri în tabelul de blocare. Și acesta este în esență comportamentul fundamental al Postgres.

Mulți oameni cred că, dacă într-o bază de date blocați 100 de rânduri, atunci va trebui să creați 100 de intrări de blocare. Dacă blochez 1 de rânduri deodată, atunci voi avea nevoie de 000 de astfel de interogări. Și dacă am nevoie de un milion sau un miliard de blocat. Dar dacă facem asta, nu va funcționa foarte bine. Dacă ați folosit un sistem care creează intrări de blocare pentru fiecare rând în parte, atunci puteți vedea că acest lucru este complicat. Pentru că trebuie să definiți imediat un tabel de blocare care poate depăși, dar Postgres nu face asta.

Și ceea ce este cu adevărat important la acest slide este că demonstrează clar că există un alt sistem care rulează în interiorul MVCC care blochează rândurile individuale. Deci, atunci când blocați miliarde de rânduri, Postgres nu creează un miliard de comenzi de blocare separate. Și acest lucru are un efect foarte bun asupra productivității.

Deblocarea Postgres Lock Manager. Bruce Momjian

Ce zici de o actualizare? Actualizez rândul acum și puteți vedea că a efectuat două operații diferite simultan. A blocat tabelul în același timp, dar a blocat și indexul. Și trebuia să blocheze indexul pentru că există constrângeri unice pe acest tabel. Și vrem să ne asigurăm că nimeni nu îl schimbă, așa că îl blocăm.

Deblocarea Postgres Lock Manager. Bruce Momjian

Ce se întâmplă dacă vreau să actualizez două rânduri? Și vedem că se comportă la fel. Facem de două ori mai multe actualizări, dar exact același număr de linii de blocare.

Dacă vă întrebați cum face Postgres acest lucru, va trebui să ascultați discuțiile mele despre MVCC pentru a afla cum Postgres marchează intern aceste rânduri pe care le modifică. Și Postgres are un mod în care face asta, dar nu o face la nivel de blocare a mesei, o face la un nivel mai scăzut și mai eficient.

Deblocarea Postgres Lock Manager. Bruce Momjian

Dacă vreau să șterg ceva? Dacă șterg, de exemplu, un rând și mai am cele două intrări de blocare și chiar dacă vreau să le șterg pe toate, ele sunt încă acolo.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și, de exemplu, vreau să inserez 1 de linii, apoi fie șterge, fie adaug 000 de linii, apoi acele linii individuale pe care le adaug sau le modific, nu sunt înregistrate aici. Sunt scrise la un nivel inferior în cadrul seriei în sine. Și în timpul discursului MVCC am vorbit despre asta în detaliu. Dar este foarte important atunci când analizați blocările să vă asigurați că blocați la nivel de tabel și că nu vedeți cum sunt înregistrate rândurile individuale aici.

Deblocarea Postgres Lock Manager. Bruce Momjian

Dar blocarea explicită?

Deblocarea Postgres Lock Manager. Bruce Momjian

Dacă dau clic pe reîmprospătare, am două rânduri blocate. Și dacă le selectez pe toate și dau clic pe „actualizează peste tot”, atunci mai am două înregistrări de blocare.

Deblocarea Postgres Lock Manager. Bruce Momjian

Nu creăm înregistrări separate pentru fiecare rând în parte. Pentru că atunci productivitatea scade, poate fi prea multă. Și s-ar putea să ne aflăm într-o situație neplăcută.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și același lucru, dacă facem shared, le putem face toate de 30 de ori.

Deblocarea Postgres Lock Manager. Bruce Momjian

Ne restaurăm tabelul, ștergem totul, apoi inserăm din nou un rând.

Deblocarea Postgres Lock Manager. Bruce Momjian

Un alt comportament pe care îl vedeți în Postgres, care este un comportament foarte bine cunoscut și dorit, este că puteți face o actualizare sau o selectare. Și poți face asta în același timp. Și select nu blochează actualizarea și același lucru în direcția opusă. Îi spunem cititorului să nu blocheze scriitorul, iar scriitorul nu l-a blocat pe cititor.

Vă voi arăta un exemplu în acest sens. Voi face o alegere acum. Vom face apoi INSERT. Și apoi puteți vedea - 694. Puteți vedea ID-ul tranzacției care a efectuat această inserare. Și așa funcționează.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și dacă mă uit la ID-ul meu backend acum, acum este 695.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și pot vedea 695 care apar în tabelul meu.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și dacă actualizez aici astfel, atunci primesc un caz diferit. În acest caz, 695 este o blocare exclusivă, iar actualizarea are același comportament, dar nu există niciun conflict între ele, ceea ce este destul de neobișnuit.

Și puteți vedea că în partea de sus este ShareLock, iar în partea de jos este ExclusiveLock. Și ambele tranzacții au funcționat.

Și trebuie să ascultați discursul meu la MVCC pentru a înțelege cum se întâmplă asta. Dar aceasta este o ilustrare că o puteți face în același timp, adică faceți o SELECTARE și o UPDATE în același timp.

Deblocarea Postgres Lock Manager. Bruce Momjian

Să resetam și să mai facem o operațiune.

Deblocarea Postgres Lock Manager. Bruce Momjian

Dacă încercați să rulați două actualizări simultan pe același rând, acesta va fi blocat. Și amintiți-vă, am spus că cititorul nu blochează scriitorul, iar scriitorul nu blochează cititorul, ci un scriitor blochează un alt scriitor. Adică, nu putem avea doi oameni să actualizeze același rând în același timp. Trebuie să așteptați până când unul dintre ele se termină.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și pentru a ilustra acest lucru, mă voi uita la tabelul Lockdemo. Și ne vom uita la un rând. Per tranzacție 698.

Am actualizat acest lucru la 2. 699 este prima actualizare. Și a avut succes sau se află într-o tranzacție în așteptare și așteaptă să confirmăm sau să anulăm.

Deblocarea Postgres Lock Manager. Bruce Momjian

Dar uită-te la altceva - 2/51 este prima noastră tranzacție, prima noastră sesiune. 3/112 este a doua cerere venită din partea de sus care a schimbat acea valoare în 3. Și dacă observi, cea de sus s-a blocat singur, adică 699. Dar 3/112 nu a acordat blocarea. Coloana Lock_mode spune ce așteaptă. Se așteaptă la 699. Și dacă te uiți unde este 699, este mai mare. Și ce a făcut prima ședință? Ea a creat un blocaj exclusiv pentru propriul ID de tranzacție. Așa procedează Postgres. Își blochează propriul ID de tranzacție. Și dacă doriți să așteptați ca cineva să confirme sau să anuleze, atunci trebuie să așteptați cât timp există o tranzacție în așteptare. Și de aceea putem vedea o linie ciudată.

Să ne uităm din nou. În stânga vedem ID-ul nostru de procesare. În a doua coloană vedem ID-ul nostru de tranzacție virtuală, iar în a treia vedem lock_type. Ce înseamnă acest lucru? În esență, ceea ce spune este că blochează ID-ul tranzacției. Dar observați că toate rândurile din partea de jos spun relație. Și așa ai două tipuri de încuietori pe masă. Există o blocare a relației. Și apoi există blocarea tranzacției, unde blocați singur, care este exact ceea ce se întâmplă pe primul rând sau în partea de jos, unde este tranzacția, unde așteptăm ca 699 să-și termine operațiunea.

Voi vedea ce se întâmplă aici. Și aici se întâmplă două lucruri simultan. Te uiți la un ID de blocare a tranzacției din primul rând care se blochează singur. Și se blochează pentru a-i face pe oameni să aștepte.

Dacă te uiți la a șasea linie, este aceeași intrare ca prima. Și, prin urmare, tranzacția 6 este blocată. 699 este, de asemenea, cu autoblocare. Și apoi, în rândul de jos, veți vedea că așteptăm ca 700 să-și termine funcționarea.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și în lock_type, tuple vezi numere.

Deblocarea Postgres Lock Manager. Bruce Momjian

Puteți vedea că este 0/10. Și acesta este numărul paginii și, de asemenea, decalajul acestui rând anume.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și vezi că devine 0/11 când actualizăm.

Deblocarea Postgres Lock Manager. Bruce Momjian

Dar în realitate este 0/10, pentru că există o așteptare pentru această operație. Avem ocazia să vedem că acesta este serialul pe care aștept să-l confirm.

Deblocarea Postgres Lock Manager. Bruce Momjian

Odată ce l-am confirmat și am apăsat pe commit, iar când actualizarea se termină, aceasta este ceea ce primim din nou. Tranzacția 700 este singura blocare, nu așteaptă pe nimeni altcineva pentru că a fost comisă. Pur și simplu așteaptă finalizarea tranzacției. Odată ce 699 se epuizează, nu mai așteptăm nimic. Și acum tranzacția 700 spune că totul este în regulă, că are toate blocajele de care are nevoie pe toate mesele permise.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și pentru a complica și mai mult acest lucru, creăm o altă vedere, care de data aceasta ne va oferi o ierarhie. Nu mă aștept să înțelegeți această cerere. Dar asta ne va oferi o imagine mai clară a ceea ce se întâmplă.

Deblocarea Postgres Lock Manager. Bruce Momjian

Aceasta este o vedere recursivă care are și o altă secțiune. Și apoi aduce totul din nou împreună. Să folosim asta.

Deblocarea Postgres Lock Manager. Bruce Momjian

Ce se întâmplă dacă facem trei actualizări simultane și spunem că rândul este acum trei. Și vom schimba 3 cu 4.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și aici vedem 4. Și ID-ul tranzacției 702.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și apoi voi schimba 4 cu 5. Și 5 cu 6 și 6 cu 7. Și voi alinia un număr de oameni care vor aștepta ca această tranzacție să se încheie.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și totul devine clar. Care este primul rând? Acesta este 702. Acesta este ID-ul tranzacției care a stabilit inițial această valoare. Ce este scris în coloana mea Acordat? Am semne f. Acestea sunt actualizările mele care (5, 6, 7) nu pot fi aprobate deoarece așteptăm încheierea tranzacției ID 702. Acolo avem blocarea ID-ului tranzacției. Și acest lucru are ca rezultat 5 blocări de ID tranzacționale.

Și dacă te uiți la 704, la 705, nu s-a scris nimic acolo, pentru că ei nu știu încă ce se întâmplă. Pur și simplu scriu că habar nu au ce se întâmplă. Și vor merge doar la culcare pentru că așteaptă ca cineva să termine și să fie trezit atunci când va avea ocazia să schimbe rândurile.

Deblocarea Postgres Lock Manager. Bruce Momjian

Așa arată. Este clar că toți așteaptă linia a 12-a.

Deblocarea Postgres Lock Manager. Bruce Momjian

Aceasta este ceea ce am văzut aici. Iată 0/12.

Deblocarea Postgres Lock Manager. Bruce Momjian

Deci, odată ce prima tranzacție este aprobată, puteți vedea aici cum funcționează ierarhia. Și acum totul devine clar. Toate devin curate. Și de fapt încă așteaptă.

Deblocarea Postgres Lock Manager. Bruce Momjian

Iată ce se întâmplă. 702 comite. Și acum 703 primește această blocare a rândului, apoi 704 începe să aștepte ca 703 să se angajeze. Și 705 așteaptă și asta. Și când toate acestea sunt finalizate, ei se curăță. Și aș dori să subliniez că toată lumea se aliniază. Și aceasta este foarte asemănătoare cu o situație într-un ambuteiaj când toată lumea așteaptă prima mașină. Prima mașină se oprește și toată lumea se aliniază într-o coadă lungă. Apoi se mișcă, apoi următoarea mașină poate merge înainte și își poate bloca etc.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și dacă acest lucru nu vi s-a părut suficient de complicat, atunci vă vom vorbi acum despre blocaje. Nu știu care dintre voi i-ai întâlnit. Aceasta este o problemă destul de comună în sistemele de baze de date. Dar blocajele sunt atunci când o sesiune așteaptă ca o altă sesiune să facă ceva. Și în acest moment o altă ședință așteaptă prima ședință pentru a face ceva.

Și, de exemplu, dacă Ivan spune: „Dă-mi ceva”, iar eu spun: „Nu, ți-l dau doar dacă îmi dai altceva”. Și el spune: „Nu, nu ți-l dau dacă nu mi-l dai mie.” Și ajungem într-o situație de blocaj. Sunt sigur că Ivan nu va face asta, dar înțelegeți ce înseamnă că avem doi oameni care vor să obțină ceva și nu sunt gata să le dea până când cealaltă persoană le dă ceea ce își doresc. Și nu există nicio soluție.

Și în esență, baza de date trebuie să detecteze acest lucru. Și apoi trebuie să ștergeți sau să închideți una dintre sesiuni, pentru că altfel vor rămâne acolo pentru totdeauna. Și o vedem în baze de date, o vedem în sistemele de operare. Și în toate locurile în care avem procese paralele, acest lucru se poate întâmpla.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și acum vom instala două blocaje. Vom pune 50 și 80. În primul rând, voi actualiza de la 50 la 50. Voi primi tranzacția numărul 710.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și apoi voi schimba 80 cu 81 și 50 cu 51.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și așa va arăta. Și astfel 710 are un rând blocat, iar 711 așteaptă confirmarea. Am văzut asta când am actualizat. 710 este proprietarul seriei noastre. Și 711 așteaptă ca 710 să finalizeze tranzacția.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și chiar spune pe ce rând apar blocajele. Și aici începe să devină ciudat.

Deblocarea Postgres Lock Manager. Bruce Momjian

Acum actualizăm de la 80 la 80.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și aici încep blocajele. 710 așteaptă un răspuns de la 711, iar 711 așteaptă 710. Și acest lucru nu se va termina bine. Și nu există nicio cale de ieșire din asta. Și vor aștepta un răspuns unul de la celălalt.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și va începe să întârzie totul. Și nu vrem asta.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și Postgres are modalități de a observa când se întâmplă acest lucru. Și când se întâmplă acest lucru, primești această eroare. Și din aceasta este clar că un astfel de proces așteaptă un SHARE LOCK de la un alt proces, adică, care este blocat de procesul 711. Și acel proces aștepta să fie dat un SHARE LOCK pe un astfel de ID de tranzacție și a fost blocat de un astfel de proces. Prin urmare, aici există o situație de blocaj.

Deblocarea Postgres Lock Manager. Bruce Momjian

Există blocaje în trei căi? Este posibil? Da.

Deblocarea Postgres Lock Manager. Bruce Momjian

Introducem aceste numere într-un tabel. Schimbăm 40 în 40, facem blocare.

Deblocarea Postgres Lock Manager. Bruce Momjian

Schimbăm 60 cu 61, 80 cu 81.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și apoi schimbăm 80 și apoi bum!

Deblocarea Postgres Lock Manager. Bruce Momjian

Iar 714 îl așteaptă acum pe 715. 716 îl așteaptă pe 715. Și nu se poate face nimic în privința asta.

Deblocarea Postgres Lock Manager. Bruce Momjian

Nu mai sunt doi oameni aici, sunt deja trei oameni aici. Vreau ceva de la tine, acesta vrea ceva de la o a treia persoană, iar a treia persoană vrea ceva de la mine. Și ajungem într-o așteptare în trei căi, pentru că așteptăm cu toții ca cealaltă persoană să finalizeze ceea ce trebuie să facă.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și Postgres știe pe ce rând se întâmplă asta. Și astfel vă va oferi următorul mesaj, care arată că aveți o problemă în care trei intrări se blochează reciproc. Și aici nu există restricții. Acesta poate fi cazul în care 20 de intrări se blochează reciproc.

Deblocarea Postgres Lock Manager. Bruce Momjian

Următoarea problemă este serializabilă.

Deblocarea Postgres Lock Manager. Bruce Momjian

Dacă blocare specială serializabilă.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și revenim la 719. Ieșirea sa este destul de normală.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și puteți face clic pentru a face tranzacția din serializabil.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și îți dai seama că acum ai un alt tip de blocare SA - înseamnă serializabil.

Deblocarea Postgres Lock Manager. Bruce Momjian

Deblocarea Postgres Lock Manager. Bruce Momjian

Și așa avem un nou tip de blocare numit SARieadLock, care este o blocare serial și vă permite să introduceți seriale.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și, de asemenea, puteți introduce indecși unici.

Deblocarea Postgres Lock Manager. Bruce Momjian

În acest tabel avem indecși unici.

Deblocarea Postgres Lock Manager. Bruce Momjian

Deci, dacă pun numărul 2 aici, deci am un 2. Dar în partea de sus, am pus încă 2 inch. Și puteți vedea că 721 are o blocare exclusivă. Dar acum 722 așteaptă ca 721 să-și termine operațiunea pentru că nu poate introduce 2 până nu știe ce se va întâmpla cu 721.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și dacă facem subtranzacție.

Deblocarea Postgres Lock Manager. Bruce Momjian

Aici avem 723.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și dacă salvăm punctul și apoi îl actualizăm, atunci obținem un nou ID de tranzacție. Acesta este un alt tipar de comportament de care trebuie să fii conștient. Dacă returnăm acest lucru, atunci ID-ul tranzacției dispare. 724 pleacă. Dar acum avem 725.

Deci ce încerc să fac aici? Încerc să vă arăt exemple de încuietori neobișnuite pe care le puteți găsi: fie că este vorba de blocări serializabile sau SAVEPOINT, acestea sunt diferite tipuri de încuietori care vor apărea în tabelul de blocare.

Deblocarea Postgres Lock Manager. Bruce Momjian

Aceasta este crearea de blocări explicite (explicite), care au pg_advisory_lock.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și vezi că tipul de blocare este listat ca consultativ. Și aici scrie „aviz” în roșu. Și puteți bloca simultan astfel cu pg_advisory_unlock.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și în concluzie, aș vrea să vă arăt încă un lucru uluitor. Voi crea o altă vizualizare. Dar mă voi alătura tabelului pg_locks cu tabelul pg_stat_activity. Și de ce vreau să fac asta? Pentru că asta îmi va permite să văd și să văd toate sesiunile curente și să văd exact ce fel de încuietori așteaptă. Și acest lucru este destul de interesant când punem împreună tabelul de blocare și tabelul de interogări.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și aici creăm pg_stat_view.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și actualizăm rândul câte unul. Și aici vedem 724. Și apoi ne actualizăm rândul la trei. Și ce vezi aici acum? Acestea sunt solicitări, adică vedeți întreaga listă de solicitări care sunt listate în coloana din stânga. Și apoi în partea dreaptă puteți vedea blocajele și ceea ce creează. Și poate fi mai clar pentru tine, astfel încât să nu fii nevoit să te întorci la fiecare sesiune de fiecare dată și să vezi dacă trebuie să te înscrii sau nu. Ei o fac pentru noi.

O altă caracteristică care este foarte utilă este pg_blocking_pids. Probabil că nu ai auzit niciodată de ea. Ce face ea? Ne permite să spunem că pentru această sesiune 11740 ce ID-uri de proces specifice așteaptă. Și puteți vedea că 11740 așteaptă 724. Și 724 este în vârf. Și 11306 este ID-ul procesului tău. În esență, această funcție trece prin tabelul de blocare. Și știu că e puțin complicat, dar reușești să înțelegi. În esență, această funcție parcurge acest tabel de blocare și încearcă să găsească unde este dat acestui ID de proces blocările pe care le așteaptă. Și încearcă, de asemenea, să descopere ce ID de proces are procesul care așteaptă blocarea. Deci puteți rula această funcție pg_blocking_pids.

Și acest lucru poate fi foarte util. Am adăugat asta doar în versiunea 9.6, deci această caracteristică are doar 5 ani, dar este foarte, foarte utilă. Și același lucru este valabil și pentru a doua cerere. Arată exact ceea ce trebuie să vedem.

Deblocarea Postgres Lock Manager. Bruce Momjian

Despre asta am vrut să vă vorbesc. Și așa cum mă așteptam, ne-am folosit tot timpul pentru că erau atât de multe tobogane. Și diapozitivele sunt disponibile pentru descărcare. Aș dori să vă mulțumesc că sunteți aici. Sunt sigur că vă veți bucura de restul conferinței, vă mulțumesc foarte mult!

Întrebări:

De exemplu, dacă încerc să actualizez rândurile și a doua sesiune încearcă să șterg întregul tabel. Din câte am înțeles, ar trebui să existe ceva de genul o blocare cu intenție. Există așa ceva în Postgres?

Deblocarea Postgres Lock Manager. Bruce Momjian

Să ne întoarcem la început. Vă puteți aminti că atunci când faceți ceva, de exemplu când faceți o SELECTARE, emitem un AccessShareLock. Și acest lucru împiedică scăparea mesei. Deci, dacă, de exemplu, doriți să actualizați un rând dintr-un tabel sau să ștergeți un rând, atunci cineva nu poate șterge întregul tabel în același timp, deoarece țineți acest AccessShareLock peste întregul tabel și peste rând. Și odată ce ați terminat, ei îl pot șterge. Dar în timp ce schimbi direct ceva acolo, ei nu vor putea să o facă.

Sa o facem din nou. Să trecem la exemplul de ștergere. Și vezi cum există o blocare exclusivă pe rândul de deasupra întregului tabel.

Va arăta ca un blocaj exclusiv, nu?

Da, seamănă. Înțeleg despre ce vorbești. Vrei să spui că dacă fac un SELECT, atunci am un ShareExclusive și apoi îl fac Row Exclusive, devine asta o problemă? Dar, în mod surprinzător, acest lucru nu reprezintă o problemă. Se pare că crește gradul de blocare, dar în esență am o blocare care împiedică ștergerea. Și acum, când fac această blocare mai puternică, încă împiedică ștergerea. Deci nu e ca și cum aș urca. Adică a împiedicat să se întâmple și când era la un nivel inferior, așa că atunci când îi ridic nivelul, tot împiedică ștergerea tabelului.

Înțeleg despre ce vorbești. Nu există niciun caz de escaladare a blocării, în care încercați să renunțați la o blocare pentru a introduce una mai puternică. Aici doar crește această prevenție în general, astfel încât nu provoacă niciun conflict. Dar este o întrebare bună. Vă mulțumesc foarte mult că ați întrebat asta!

Ce trebuie să facem pentru a evita o situație de blocaj când avem multe sesiuni, un număr mare de utilizatori?

Postgres observă automat situațiile de blocaj. Și va șterge automat una dintre sesiuni. Singura modalitate de a evita blocarea dead este să blocați oamenii în aceeași ordine. Deci, când te uiți la aplicația ta, adesea motivul blocajelor... Să ne imaginăm că vreau să blochez două lucruri diferite. O aplicație blochează tabelul 1, iar o altă aplicație blochează 2 și apoi tabelul 1. Și cel mai simplu mod de a evita blocajele este să vă uitați la aplicația dvs. și să încercați să vă asigurați că blocarea are loc în aceeași ordine în toate aplicațiile. Și asta de obicei elimină 80% din probleme, pentru că tot felul de oameni scriu aceste aplicații. Și dacă le blocați în aceeași ordine, atunci nu întâlniți o situație de blocaj.

Vă mulțumesc foarte mult pentru performanță! Ai vorbit despre vacuum full și, dacă am înțeles bine, vacuum full distorsionează ordinea înregistrărilor în stocare separată, așa că păstrează înregistrările curente neschimbate. De ce vacuum full are acces exclusiv la blocare și de ce intră în conflict cu operațiunile de scriere?

Asta e o intrebare buna. Motivul este că vidul plin ia masa. Și, în esență, creăm o nouă versiune a tabelului. Și masa va fi nouă. Se pare că aceasta va fi o versiune complet nouă a tabelului. Și problema este că atunci când facem asta, nu vrem ca oamenii să o citească pentru că avem nevoie de ei să vadă noul tabel. Și deci aceasta se leagă de întrebarea anterioară. Dacă am putea citi în același timp, nu am fi capabili să-l mutăm și să direcționăm oamenii către o masă nouă. Ar trebui să așteptăm ca toată lumea să termine de citit acest tabel și, prin urmare, este, în esență, o situație exclusivă de blocare.
Spunem doar că blocăm de la început pentru că știm că la sfârșit vom avea nevoie de o blocare exclusivă pentru a muta pe toți la noua copie. Deci putem rezolva eventual acest lucru. Și o facem astfel cu indexare simultană. Dar acest lucru este mult mai dificil de făcut. Și acest lucru se referă foarte mult la întrebarea dvs. anterioară despre blocarea exclusivă.

Este posibil să adăugați timeout de blocare la Postgres? În Oracle, pot, de exemplu, să scriu „select to update” și să aștept 50 de secunde înainte de a actualiza. A fost bun pentru aplicație. Dar în Postgres, fie trebuie să o fac imediat și să nu aștept deloc, fie să aștept până la un timp.

Da, puteți alege un timeout pentru încuietori, pentru încuietori. De asemenea, puteți emite o comandă fără niciun fel, care va... dacă nu puteți obține imediat blocarea. Prin urmare, fie un timeout de blocare, fie altceva care vă va permite să faceți acest lucru. Acest lucru nu se face la nivel sintactic. Acest lucru se face ca o variabilă pe server. Uneori, acest lucru nu poate fi folosit.

Poți deschide slide-ul 75?

Da.

Deblocarea Postgres Lock Manager. Bruce Momjian

Și întrebarea mea este următoarea. De ce ambele procese de actualizare așteaptă 703?

Și aceasta este o întrebare grozavă. Nu înțeleg, apropo, de ce Postgres face asta. Dar când a fost creat 703, se aștepta la 702. Și când apar 704 și 705, se pare că nu știu la ce se așteaptă pentru că încă nu este nimic acolo. Și Postgres procedează astfel: când nu poți obține un blocaj, scrie „Ce rost are să te proceseze?”, pentru că deja aștepți pe cineva. Așa că îl vom lăsa să atârne în aer, nu îl va actualiza deloc. Dar ce sa întâmplat aici? Imediat ce 702 a finalizat procesul și 703 a primit blocarea, sistemul a revenit înapoi. Și ea a spus că acum avem doi oameni care așteaptă. Și apoi să le actualizăm împreună. Și să indicam că amândoi se așteaptă.

Nu știu de ce Postgres face asta. Dar există o problemă numită f... Mi se pare că acesta nu este un termen în rusă. Acesta este momentul în care toată lumea așteaptă un castel, chiar dacă există 20 de autorități care așteaptă castelul. Și deodată toți se trezesc în același timp. Și toată lumea începe să încerce să reacționeze. Dar sistemul face ca toată lumea să așteaptă 703. Pentru că toți așteaptă și imediat îi vom alinia pe toți. Și dacă apare orice altă cerere nouă care a fost generată după aceasta, de exemplu, 707, atunci va exista din nou gol.

Și mi se pare că asta se face ca să putem spune că la această etapă 702 așteaptă 703, iar toți cei care vin după aceea nu vor avea nicio intrare în acest domeniu. Dar de îndată ce primul chelner pleacă, toți cei care așteptau în acel moment înainte de actualizare primesc același token. Și cred că acest lucru se face astfel încât să putem procesa în ordine, astfel încât acestea să fie comandate corect.

Mereu am privit asta ca pe un fenomen destul de ciudat. Pentru că aici, de exemplu, nu le enumerăm deloc. Dar mi se pare că de fiecare dată când dăm o nouă lacăt, ne uităm la toți cei care sunt în proces de așteptare. Apoi le aliniem pe toate. Și apoi orice nou care intră intră în coadă doar când următoarea persoană a terminat procesarea. Foarte buna intrebarea. Vă mulțumesc foarte mult pentru întrebarea dvs.!

Mi se pare că este mult mai logic când 705 se așteaptă la 704.

Dar problema aici este următoarea. Tehnic, te poți trezi pe unul sau pe altul. Și așa ne vom trezi unul sau altul. Dar ce se întâmplă în sistem? Puteți vedea cum 703 din partea de sus și-a blocat propriul ID de tranzacție. Așa funcționează Postgres. Și 703 este blocat de propriul ID de tranzacție, așa că dacă cineva vrea să aștepte, atunci va aștepta 703. Și, în esență, 703 se finalizează. Și numai după finalizarea sa se trezește unul dintre procese. Și nu știm care va fi exact acest proces. Apoi procesăm totul treptat. Dar nu este clar care proces este trezit primul, deoarece ar putea fi oricare dintre aceste procese. În esență, aveam un planificator care spunea că acum putem activa oricare dintre aceste procese. Alegem doar unul la întâmplare. Așa că amândoi trebuie remarcați pentru că le putem trezi pe oricare dintre ei.

Și problema este că avem CP-infinity. Și, prin urmare, este destul de probabil să-l putem trezi pe cel de mai târziu. Și dacă, de exemplu, îl trezim pe cel de mai târziu, îl vom aștepta pe cel care tocmai a primit blocul, așa că nu stabilim exact cine va fi trezit primul. Pur și simplu creăm o astfel de situație, iar sistemul îi va trezi într-o ordine aleatorie.

Există articole despre încuietori de Egor Rogov. Uite, sunt și ele interesante și utile. Subiectul, desigur, este teribil de complex. Mulțumesc foarte mult, Bruce!

Sursa: www.habr.com

Adauga un comentariu