Brūsa Momdžana 2020. gada runas “Postgresas slēdzenes pārvaldnieka atbloķēšana” stenogramma.
(Piezīme: visus SQL vaicājumus no slaidiem var iegūt no šīs saites:
Sveiki! Ir lieliski atkal būt šeit, Krievijā. Piedod, ka nevarēju ierasties pagājušajā gadā, bet šogad mums ar Ivanu ir lieli plāni. Ceru šeit būt daudz biežāk. Man patīk ierasties Krievijā. Es apmeklēšu Tjumeņu, Tveru. Esmu ļoti priecīga, ka varēšu apmeklēt šīs pilsētas.
Mani sauc Brūss Momdzjans. Es strādāju uzņēmumā EnterpriseDB un strādāju ar Postgres vairāk nekā 23 gadus. Es dzīvoju Philadelphia, USA. Es ceļoju apmēram 90 dienas gadā. Un es apmeklēju apmēram 40 konferences. Mans
Es biju skolotājs, profesors, pirms sāku strādāt ar Postgres. Un es ļoti priecājos, ka tagad varēšu jums pastāstīt to, ko es jums teikšu. Šī ir viena no manām interesantākajām prezentācijām. Un šajā prezentācijā ir 110 slaidi. Mēs sāksim runāt ar vienkāršām lietām, un beigās ziņojums kļūs arvien sarežģītāks un kļūs diezgan sarežģīts.
Šī ir diezgan nepatīkama saruna. Bloķēšana nav vispopulārākā tēma. Mēs vēlamies, lai tas kaut kur pazūd. Tas ir kā iet pie zobārsta.
- Bloķēšana ir problēma daudziem cilvēkiem, kuri strādā datu bāzēs un kuriem vienlaikus darbojas vairāki procesi. Viņiem ir nepieciešama bloķēšana. Tas ir, šodien es jums sniegšu pamatzināšanas par bloķēšanu.
- Darījumu ID. Šī ir diezgan garlaicīga prezentācijas daļa, taču tās ir jāsaprot.
- Tālāk mēs runāsim par bloķēšanas veidiem. Šī ir diezgan mehāniska daļa.
- Tālāk mēs sniegsim dažus bloķēšanas piemērus. Un to būs diezgan grūti saprast.
Parunāsim par bloķēšanu.
Mūsu terminoloģija ir diezgan sarežģīta. Cik daudzi no jums zina, no kurienes nāk šis fragments? Divi cilvēki. Tas ir no spēles ar nosaukumu Colossal Cave Adventure. Manuprāt, tā bija uz tekstu balstīta datorspēle 80. gados. Tur bija jāiet alā, labirintā, un teksts mainījās, bet saturs katru reizi bija aptuveni vienāds. Tā es atceros šo spēli.
Un šeit mēs redzam to slēdzeņu nosaukumu, kas mums nonāca no Oracle. Mēs tos lietojam.
Šeit mēs redzam terminus, kas mani mulsina. Piemēram, SHARE UPDATE ECXLUSIVE. Nākamais SHARE RAW ECXLUSIVE. Godīgi sakot, šie nosaukumi nav īsti skaidri. Mēs centīsimies tos izskatīt sīkāk. Daži satur vārdu “dalīties”, kas nozīmē atdalīties. Daži satur vārdu “ekskluzīvs”. Daži satur abus šos vārdus. Es vēlētos sākt ar to, kā šīs slēdzenes darbojas.
Un vārds “piekļuve” arī ir ļoti svarīgs. Un vārdi “rinda” ir virkne. Tas ir, piekļuves sadale, rindu sadale.
Vēl viena problēma, kas jāsaprot Postgres, kuru es diemžēl nevarēšu aptvert savā runā, ir MVCC. Manā vietnē man ir atsevišķa prezentācija par šo tēmu. Un, ja jūs domājat, ka šī prezentācija ir grūta, MVCC, iespējams, ir mans grūtākais. Un, ja ir interese, to var noskatīties mājaslapā. Varat noskatīties video.
Vēl viena lieta, kas mums ir jāsaprot, ir darījumu ID. Daudzi darījumi nevar darboties bez unikāliem identifikatoriem. Un šeit mums ir skaidrojums par to, kas ir darījums. Postgres ir divas darījumu numerācijas sistēmas. Es zinu, ka tas nav ļoti skaists risinājums.
Ņemiet vērā arī to, ka slaidi būs diezgan grūti saprotami, tāpēc tas, kas ir izcelts sarkanā krāsā, ir tas, kam jums jāpievērš uzmanība.
Paskatīsimies. Darījuma numurs ir iezīmēts sarkanā krāsā. Šeit ir parādīta funkcija SELECT pg_back. Tas atgriež manu darījumu un darījuma ID.
Vēl viena lieta, ja jums patīk šī prezentācija un vēlaties to palaist savā datu bāzē, varat doties uz šo saiti rozā krāsā un lejupielādēt šīs prezentācijas SQL. Un jūs varat to vienkārši palaist savā PSQL, un visa prezentācija nekavējoties būs jūsu ekrānā. Tajā nebūs ziedu, bet vismaz mēs to varam redzēt.
Šajā gadījumā mēs redzam darījuma ID. Šis ir numurs, ko mēs viņai piešķīrām. Un Postgres ir vēl viens darījuma ID veids, ko sauc par virtuālā darījuma ID
Un mums tas ir jāsaprot. Tas ir ļoti svarīgi, pretējā gadījumā mēs nevarēsim saprast bloķēšanu Postgresā.
Virtuālais darījuma ID ir darījuma ID, kas nesatur pastāvīgas vērtības. Piemēram, ja es palaižu komandu SELECT, tad visticamāk nemainīšu datubāzi, neko nebloķēšu. Tātad, izpildot vienkāršu SELECT, mēs šim darījumam nepiešķiram pastāvīgu ID. Mēs viņai tur dodam tikai virtuālo ID.
Un tas uzlabo Postgres veiktspēju, uzlabo tīrīšanas iespējas, tāpēc virtuālā darījuma ID sastāv no diviem cipariem. Pirmais cipars pirms slīpsvītras ir aizmugursistēmas ID. Un labajā pusē mēs redzam tikai skaitītāju.
Tāpēc, ja izpildu pieprasījumu, tiek teikts, ka aizmugursistēmas ID ir 2.
Un, ja es izpildu virkni šādu darījumu, mēs redzam, ka skaitītājs palielinās katru reizi, kad izpildu vaicājumu. Piemēram, kad es izpildu vaicājumu 2/10, 2/11, 2/12 utt.
Ņemiet vērā, ka šeit ir divas kolonnas. Kreisajā pusē redzams virtuālā darījuma ID – 2/12. Un labajā pusē mums ir pastāvīgs darījuma ID. Un šis lauks ir tukšs. Un šis darījums nemaina datu bāzi. Tāpēc es tam nepiešķiru pastāvīgu darījuma ID.
Tiklīdz es palaižu analīzes komandu ((ANALĪZĒ)), tas pats vaicājums man piešķir pastāvīgu darījuma ID. Paskatieties, kā tas mums ir mainījies. Man agrāk nebija šī ID, bet tagad man tas ir.
Tātad šeit ir vēl viens pieprasījums, vēl viens darījums. Virtuālā darījuma numurs ir 2/13. Un, ja es prasīšu pastāvīgu darījuma ID, tad, izpildot vaicājumu, es to saņemšu.
Tātad, vēl vienu reizi. Mums ir virtuālais darījuma ID un pastāvīgs darījuma ID. Vienkārši saprotiet šo punktu, lai saprastu Postgres uzvedību.
Mēs pārejam uz trešo sadaļu. Šeit mēs vienkārši izstaigāsim dažādu veidu slēdzenes Postgresā. Tas nav īpaši interesanti. Pēdējā sadaļa būs daudz interesantāka. Bet jāņem vērā elementāras lietas, jo pretējā gadījumā mēs nesapratīsim, kas notiks tālāk.
Mēs izskatīsim šo sadaļu, apskatīsim katru slēdzenes veidu. Un es jums parādīšu piemērus, kā tie tiek instalēti, kā tie darbojas, es parādīšu dažus vaicājumus, kurus varat izmantot, lai redzētu, kā Postgres darbojas bloķēšana.
Lai izveidotu vaicājumu un redzētu, kas notiek programmā Postgres, vaicājums ir jāizdod sistēmas skatā. Šajā gadījumā pg_lock ir iezīmēts sarkanā krāsā. Pg_lock ir sistēmas tabula, kas norāda, kādas slēdzenes pašlaik tiek izmantotas programmā Postgres.
Tomēr man ir ļoti grūti parādīt pg_lock vienu pašu, jo tas ir diezgan sarežģīts. Tāpēc es izveidoju skatu, kas parāda pg_locks. Un tas man arī dara zināmu darbu, kas ļauj man labāk saprast. Tas nozīmē, ka tajā nav iekļautas manas slēdzenes, mana sesija utt. Tā ir tikai standarta SQL, un tā ļauj jums labāk parādīt, kas notiek.
Vēl viena problēma ir tā, ka šis skats ir ļoti plašs, tāpēc man ir jāveido otrs - lockview2.
Un tas man parāda vairāk kolonnu no tabulas. Un vēl viens, kas parāda man pārējās kolonnas. Tas ir diezgan sarežģīti, tāpēc es centos to pasniegt pēc iespējas vienkāršāk.
Tāpēc mēs izveidojām tabulu ar nosaukumu Lockdemo. Un mēs tur izveidojām vienu rindiņu. Šī ir mūsu tabulas paraugs. Mēs veidosim sadaļas, lai parādītu slēdzeņu piemērus.
Tātad, viena rinda, viena kolonna. Pirmo slēdzenes veidu sauc ACCESS SHARE. Šī ir vismazāk ierobežojošā bloķēšana. Tas nozīmē, ka tas praktiski nav pretrunā ar citām slēdzenēm.
Un, ja mēs vēlamies skaidri definēt slēdzeni, mēs palaižam komandu “bloķēšanas tabula”. Un tas acīmredzami bloķēs, t.i., režīmā ACCESS SHARE mēs palaižam bloķēšanas tabulu. Un, ja es palaižu PSQL fonā, es sāku otro sesiju no pirmās sesijas šādā veidā. Tas ir, ko es šeit darīšu? Es dodos uz citu sesiju un saku tai "parādīt man šī pieprasījuma bloķēšanas skatu". Un šeit man šajā tabulā ir AccessShareLock. Tas ir tieši tas, ko es pieprasīju. Un viņš saka, ka bloks ir piešķirts. Ļoti vienkārši.
Tālāk, ja skatāmies uz otro kolonnu, tad tur nekā nav. Tās ir tukšas.
Un, ja es palaižu komandu "SELECT", tas ir netiešais (tiešais) veids, kā pieprasīt AccessShareLock. Tāpēc es atbrīvoju savu tabulu un izpildu vaicājumu, un vaicājums atgriež vairākas rindas. Un vienā no rindām mēs redzam AccessShareLock. Tādējādi SELECT uz galda izsauc AccessShareLock. Un tas praktiski ne ar ko nav pretrunā, jo tā ir zema līmeņa slēdzene.
Ko darīt, ja es palaižu SELECT un man ir trīs dažādas tabulas? Iepriekš es izmantoju tikai vienu tabulu, tagad es izmantoju trīs: pg_class, pg_namespace un pg_attribute.
Un tagad, skatoties uz vaicājumu, trīs tabulās redzu 9 AccessShareLocks. Kāpēc? Trīs tabulas ir iezīmētas zilā krāsā: pg_attribute, pg_class, pg_namespace. Taču varat arī redzēt, ka visiem indeksiem, kas ir definēti, izmantojot šīs tabulas, ir arī AccessShareLock.
Un šī ir slēdzene, kas praktiski nav pretrunā ar citiem. Un viss, ko tas dara, ir vienkārši neļauj mums atiestatīt tabulu, kamēr mēs to atlasām. Tam ir jēga. Tas ir, ja mēs atlasām tabulu, tā tajā brīdī pazūd, tad tas ir nepareizi, tāpēc AccessShare ir zema līmeņa bloķēšana, kas mums norāda: "Nenometiet šo tabulu, kamēr es strādāju".. Būtībā tas ir viss, ko viņa dara.
ROW SHARE — šī slēdzene ir nedaudz atšķirīga.
Ņemsim piemēru. SELECT ROW SHARE metodi katras rindas bloķēšanai atsevišķi. Tādā veidā neviens nevar tos izdzēst vai mainīt, kamēr mēs tos skatāmies.
Tātad, ko dara SHARE LOCK? Mēs redzam, ka SELECT darījuma ID ir 681. Un tas ir interesanti. Kas te notika? Pirmo reizi mēs redzam numuru laukā “Bloķēt”. Mēs paņemam darījuma ID, un tas saka, ka tas to bloķē ekskluzīvajā režīmā. Tas tikai saka, ka man ir rinda, kas ir tehniski bloķēta kaut kur tabulā. Bet kur tieši viņš nesaka. Mēs to aplūkosim sīkāk nedaudz vēlāk.
Šeit mēs sakām, ka slēdzeni lietojam mēs.
Tātad ekskluzīva slēdzene skaidri norāda, ka tā ir ekskluzīva. Un arī tad, ja jūs izdzēsīsiet rindu šajā tabulā, tas notiks, kā jūs varat redzēt.
SHARE EXCLUSIVE ir garāka slēdzene.
Šī ir analizatora komanda (ANALĪZE), kas tiks izmantota.
SHARE LOCK — varat skaidri bloķēt koplietošanas režīmā.
Varat arī izveidot unikālu indeksu. Un tur jūs varat redzēt SHARE LOCK, kas ir daļa no tiem. Un tas aizslēdz galdu un uzliek SHARE LOCK.
Pēc noklusējuma tabulas SHARE LOCK nozīmē, ka citi cilvēki var lasīt tabulu, bet neviens nevar to mainīt. Un tieši tas notiek, kad izveidojat unikālu indeksu.
Ja es izveidošu unikālu vienlaicīgu indeksu, man būs cita veida bloķēšana, jo, kā jūs atceraties, vienlaicīga indeksu izmantošana samazina bloķēšanas prasību. Un, ja es izmantoju parastu slēdzeni, parastu indeksu, es tādējādi neļaušu rakstīt tabulas indeksam, kamēr tas tiek izveidots. Ja es vienlaikus izmantoju indeksu, man ir jāizmanto cita veida bloķēšana.
SHARE ROW EXCLUSIVE – atkal to var iestatīt tieši (eksplicīti).
Vai arī mēs varam izveidot noteikumu, t.i., ņemt konkrētu gadījumu, kurā tas tiks izmantots.
EKSKLUZĪVA bloķēšana nozīmē, ka neviens cits nevar mainīt galdu.
Šeit mēs redzam dažādu veidu slēdzenes.
Piemēram, ACCESS EXCLUSIVE ir bloķēšanas komanda. Piemēram, ja jūs to darāt CLUSTER table
, tad tas nozīmēs, ka neviens tur nevarēs rakstīt. Un tas bloķē ne tikai pašu tabulu, bet arī indeksus.
Šī ir otrā ACCESS EXCLUSIVE bloķēšanas lapa, kurā redzams tieši tas, ko tas bloķē tabulā. Tas bloķē atsevišķas tabulas rindas, kas ir diezgan interesanti.
Tā ir visa pamatinformācija, ko vēlējos sniegt. Mēs runājām par slēdzenēm, par darījumu ID, mēs runājām par virtuālo darījumu ID, par pastāvīgajiem darījumu ID.
Un tagad mēs apskatīsim dažus bloķējošus piemērus. Šī ir visinteresantākā daļa. Apskatīsim ļoti interesantus gadījumus. Un mans mērķis šajā prezentācijā ir sniegt jums labāku izpratni par to, ko Postgres patiesībā dara, mēģinot bloķēt noteiktas lietas. Es domāju, ka viņš ļoti labi bloķē daļas.
Apskatīsim dažus konkrētus piemērus.
Sāksim ar tabulām un vienu rindu tabulā. Ievietojot kaut ko, tabulā tiek parādīts ExclusiveLock, Transaction ID un ExclusiveLock.
Kas notiks, ja ievietošu vēl divas rindas? Un tagad mūsu tabulā ir trīs rindas. Un es ievietoju vienu rindu un saņēmu šo kā izvadi. Un, ja es ievietoju vēl divas rindas, kas tur dīvains? Šeit ir dīvaina lieta, jo es šai tabulai esmu pievienojis trīs rindas, bet man joprojām ir divas rindas bloķēšanas tabulā. Un tā būtībā ir Postgresa galvenā uzvedība.
Daudzi cilvēki domā, ka, ja datu bāzē bloķējat 100 rindas, jums būs jāizveido 100 bloķēšanas ieraksti. Ja es bloķēšu 1 rindu uzreiz, tad man vajadzēs 000 šādu vaicājumu. Un ja man vajag miljonu vai miljardu, lai bloķētu. Bet, ja mēs to darīsim, tas nedarbosies ļoti labi. Ja esat izmantojis sistēmu, kas izveido bloķēšanas ierakstus katrai atsevišķai rindai, varat redzēt, ka tas ir sarežģīti. Jo jums nekavējoties jādefinē bloķēšanas tabula, kas var pārplūst, bet Postgres to nedara.
Un šajā slaidā patiešām svarīgi ir tas, ka tas skaidri parāda, ka ir vēl viena sistēma, kas darbojas MVCC iekšpusē, kas bloķē atsevišķas rindas. Tātad, kad jūs bloķējat miljardus rindu, Postgres nerada miljardu atsevišķu bloķēšanas komandu. Un tas ļoti labi ietekmē produktivitāti.
Kā ar atjauninājumu? Es tagad atjauninu rindu, un jūs varat redzēt, ka tā ir veikusi divas dažādas darbības vienlaikus. Tajā pašā laikā tas bloķēja tabulu, bet arī bloķēja indeksu. Un viņam vajadzēja bloķēt indeksu, jo šai tabulai ir unikāli ierobežojumi. Un mēs vēlamies, lai neviens to nemainītu, tāpēc mēs to bloķējam.
Kas notiek, ja vēlos atjaunināt divas rindas? Un mēs redzam, ka viņš uzvedas tāpat. Mēs veicam divreiz vairāk atjauninājumu, bet tieši tikpat daudz bloķēšanas līniju.
Ja vēlaties uzzināt, kā Postgres to dara, jums būs jānoklausās manas sarunas par MVCC, lai uzzinātu, kā Postgres iekšēji atzīmē šīs līnijas, kuras tā maina. Un Postgres ir veids, kā tas to dara, bet tas nedara to galda bloķēšanas līmenī, tas dara to zemākā un efektīvākā līmenī.
Ko darīt, ja es vēlos kaut ko izdzēst? Ja es izdzēšu, piemēram, vienu rindu un man joprojām ir divas bloķējošās ievades, un pat ja es vēlos tās visas izdzēst, tās joprojām ir.
Un, piemēram, es gribu ievietot 1 rindiņas, un tad vai nu dzēst, vai pievienot 000 rindiņas, tad tās atsevišķās rindas, kuras es pievienoju vai mainu, tās šeit netiek ierakstītas. Tie ir rakstīti zemākā līmenī pašā sērijā. Un MVCC runas laikā es par to runāju detalizēti. Bet tas ir ļoti svarīgi, analizējot bloķēšanu, lai pārliecinātos, ka bloķējat tabulas līmenī un ka neredzat, kā šeit tiek ierakstītas atsevišķas rindas.
Kā ar nepārprotamu bloķēšanu?
Ja noklikšķinu uz atsvaidzināt, man ir bloķētas divas rindas. Un, ja es atlasu tos visus un noklikšķinu uz “atjaunināt visur”, man joprojām ir divi bloķēšanas ieraksti.
Mēs neveidojam atsevišķus ierakstus katrai atsevišķai rindai. Jo tad produktivitāte krītas, tā var būt par daudz. Un mēs varam nonākt nepatīkamā situācijā.
Un tas pats, ja mēs kopīgojam, mēs varam to darīt visas 30 reizes.
Mēs atjaunojam savu tabulu, izdzēšam visu, pēc tam atkal ievietojam vienu rindu.
Vēl viena Postgres darbība, kas ir ļoti labi zināma un vēlama, ir tā, ka varat veikt atjaunināšanu vai atlasi. Un jūs varat to izdarīt vienlaikus. Un izvēlieties nebloķē atjaunināšanu un to pašu pretējā virzienā. Mēs sakām lasītājam nebloķēt rakstītāju, un rakstnieks nebloķēja lasītāju.
Es jums parādīšu piemēru. Es tagad izdarīšu izvēli. Pēc tam mēs veiksim INSERT. Un tad jūs varat redzēt - 694. Var redzēt darījuma ID, kas veica šo ievietošanu. Un tā tas darbojas.
Un, ja es tagad skatos uz savu aizmugursistēmas ID, tagad tas ir 695.
Un es redzu, ka manā tabulā parādās 695.
Un, ja es atjauninu šeit šādi, tad man ir cits gadījums. Šajā gadījumā 695 ir ekskluzīva slēdzene, un atjauninājumam ir tāda pati darbība, taču starp tiem nav konflikta, kas ir diezgan neparasti.
Un jūs varat redzēt, ka augšpusē tas ir ShareLock, bet apakšā tas ir ExclusiveLock. Un abi darījumi izdevās.
Un jums ir jānoklausās mana runa MVCC, lai saprastu, kā tas notiek. Bet tas ir ilustrācija, ka varat to izdarīt vienlaikus, t.i., vienlaikus veikt SELECT un UPDATE.
Atiestatīsim un veiksim vēl vienu darbību.
Ja mēģināsit palaist divus atjauninājumus vienlaikus vienā rindā, tas tiks bloķēts. Un atcerieties, es teicu, ka lasītājs nebloķē rakstītāju, un rakstnieks nebloķē lasītāju, bet viens rakstnieks bloķē citu rakstītāju. Tas nozīmē, ka divi cilvēki nevar vienlaikus atjaunināt vienu un to pašu rindu. Jums jāgaida, līdz kāds no tiem beidzas.
Un, lai to ilustrētu, es apskatīšu Lockdemo tabulu. Un mēs apskatīsim vienu rindu. Par darījumu 698.
Mēs to esam atjauninājuši uz 2. 699 ir pirmais atjauninājums. Un tas bija veiksmīgs vai atrodas neapstiprinātā darījumā un gaida, kad apstiprināsim vai atcelsim.
Bet paskatieties uz kaut ko citu — 2/51 ir mūsu pirmais darījums, mūsu pirmā sesija. 3/112 ir otrais pieprasījums, kas tika saņemts no augšas un mainīja šo vērtību uz 3. Un, ja pamanāt, augšējā bloķēja sevi, kas ir 699. Taču 3/112 nepiešķīra bloķēšanu. Slejā Lock_mode ir norādīts, ko tas gaida. Tas paredz 699. Un, ja paskatās, kur ir 699, tas ir augstāks. Un ko darīja pirmā sesija? Viņa izveidoja ekskluzīvu slēdzeni savam darījuma ID. Šādi to dara Postgres. Tas bloķē savu darījuma ID. Un, ja vēlaties gaidīt, kamēr kāds apstiprinās vai atcels, tad jums jāgaida, kamēr ir neapstiprināts darījums. Un tāpēc mēs varam redzēt dīvainu līniju.
Paskatīsimies vēlreiz. Kreisajā pusē redzams mūsu apstrādes ID. Otrajā kolonnā mēs redzam mūsu virtuālo darījuma ID, bet trešajā - lock_type. Ko tas nozīmē? Būtībā tas saka, ka tas bloķē darījuma ID. Bet ievērojiet, ka visās rindās apakšā ir norādīta saistība. Un tātad uz galda ir divu veidu slēdzenes. Ir attiecību bloķēšana. Un tad ir darījuma ID bloķēšana, kur jūs bloķējat pats, kas tieši notiek pirmajā rindā vai pašā apakšā, kur ir transakcijas ID, kur mēs gaidām 699, lai pabeigtu savu darbību.
Es paskatīšos, kas šeit notiks. Un šeit notiek divas lietas vienlaikus. Jūs skatāties uz darījuma ID bloķēšanu pirmajā rindā, kas pati bloķējas. Un viņa bloķē sevi, lai liktu cilvēkiem gaidīt.
Ja paskatās uz 6. rindiņu, tas ir tāds pats ieraksts kā pirmais. Un tāpēc 699. darījums tiek bloķēts. 700 ir arī pašbloķējošs. Un tad apakšējā rindā jūs redzēsiet, ka mēs gaidām 699, lai pabeigtu savu darbību.
Un lock_type, kortežā jūs redzat skaitļus.
Var redzēt, ka ir 0/10. Un tas ir lapas numurs, kā arī šīs konkrētās rindas nobīde.
Kad mēs atjauninām, tas kļūst par 0/11.
Bet reāli tas ir 0/10, jo uz šo operāciju ir jāgaida. Mums ir iespēja pārliecināties, ka šī ir sērija, kuras apstiprinājumu gaidu.
Kad esam to apstiprinājuši un nospieduši commit, un kad atjaunināšana ir pabeigta, mēs atkal saņemam šo. Darījums 700 ir vienīgais bloķētājs, tas negaida nevienu citu, jo tas tika izdarīts. Tas vienkārši gaida, līdz darījums tiks pabeigts. Kad 699 beidzas, mēs vairs neko negaidām. Un tagad darījums 700 saka, ka viss ir kārtībā, ka tam ir visas nepieciešamās slēdzenes uz visiem atļautajiem galdiem.
Un, lai šo visu padarītu vēl sarežģītāku, mēs izveidojam citu skatu, kas šoreiz nodrošinās mums hierarhiju. Es negaidu, ka sapratīsit šo pieprasījumu. Bet tas mums sniegs skaidrāku priekšstatu par notiekošo.
Šis ir rekursīvs skats, kuram ir arī cita sadaļa. Un tad tas atkal saved visu kopā. Izmantosim šo.
Kā būtu, ja mēs veiktu trīs vienlaicīgus atjauninājumus un teiktu, ka rinda tagad ir trīs. Un mēs mainīsim 3 pret 4.
Un šeit mēs redzam 4. Un darījuma ID 702.
Un tad es nomainīšu 4 pret 5. Un 5 pret 6, un 6 pret 7. Un es sastādīšu rindā vairākus cilvēkus, kuri gaidīs, kad šis viens darījums beigsies.
Un viss kļūst skaidrs. Kāda ir pirmā rinda? Tas ir 702. Šis ir darījuma ID, kas sākotnēji iestatīja šo vērtību. Kas ir rakstīts manā slejā Piešķirts? Man ir atzīmes f
. Šie ir mani atjauninājumi, kurus (5, 6, 7) nevar apstiprināt, jo mēs gaidām, līdz beigsies darījuma ID 702. Tur mums ir darījuma ID bloķēšana. Tā rezultātā tiek bloķēti 5 darījumu ID.
Un, ja paskatās uz 704, uz 705, tur vēl nekas nav rakstīts, jo viņi vēl nezina, kas notiek. Viņi vienkārši raksta, ka viņiem nav ne jausmas, kas notiek. Un viņi vienkārši ies gulēt, jo gaida, kad kāds beigs un tiks pamodināts, kad būs iespēja mainīt rindas.
Tas izskatās šādi. Skaidrs, ka viņi visi gaida 12. līniju.
Tas ir tas, ko mēs šeit redzējām. Lūk, 0/12.
Tātad, kad pirmais darījums ir apstiprināts, šeit varat redzēt, kā darbojas hierarhija. Un tagad viss kļūst skaidrs. Viņi visi kļūst tīri. Un patiesībā viņi joprojām gaida.
Lūk, kas notiek. 702 apņemas. Un tagad 703 saņem šo rindu bloķēšanu, un tad 704 sāk gaidīt, līdz 703 tiks veikta. Un arī 705 to gaida. Un, kad tas viss ir pabeigts, viņi sakopjas. Un vēlos norādīt, ka visi stāv rindā. Un tas ir ļoti līdzīgi situācijai sastrēgumā, kad visi gaida pirmo mašīnu. Pirmā mašīna apstājas un visi sastājas garā rindā. Tad tas kustas, tad nākamā mašīna var braukt uz priekšu un dabūt savu bloku utt.
Un, ja tas jums nešķita pietiekami sarežģīts, tagad mēs ar jums parunāsim par strupceļiem. Es nezinu, kurš no jums ar tiem ir saskāries. Tā ir diezgan izplatīta problēma datu bāzu sistēmās. Bet strupceļš ir tad, kad viena sesija gaida, kad cita sesija kaut ko darītu. Un šobrīd vēl viena sesija gaida pirmo sesiju, lai kaut ko darītu.
Un, piemēram, ja Ivans saka: “Dod man kaut ko”, un es saku: “Nē, es tev to došu tikai tad, ja tu man iedosi kaut ko citu.” Un viņš saka: "Nē, es tev to nedošu, ja tu man to nedosi." Un mēs nonākam strupceļā. Esmu pārliecināts, ka Ivans to nedarīs, bet jūs saprotat nozīmi, ka mums ir divi cilvēki, kuri vēlas kaut ko iegūt, un viņi nav gatavi to atdot, kamēr otrs viņiem neiedos to, ko viņi vēlas. Un risinājuma nav.
Un būtībā jūsu datu bāzei tas ir jāatklāj. Un tad jums ir jāizdzēš vai jāaizver kāda no sesijām, jo pretējā gadījumā tās paliks tur uz visiem laikiem. Un mēs to redzam datu bāzēs, mēs to redzam operētājsistēmās. Un visās vietās, kur mums ir paralēli procesi, tas var notikt.
Un tagad mēs uzstādīsim divus strupceļus. Mēs ieliksim 50 un 80. Pirmajā rindā es atjaunināšu no 50 uz 50. Es saņemšu darījuma numuru 710.
Un tad es nomainīšu 80 pret 81 un 50 pret 51.
Un šādi tas izskatīsies. Tātad 710 ir bloķēta rinda, un 711 gaida apstiprinājumu. Mēs to redzējām, kad atjauninājām. 710 ir mūsu sērijas īpašnieks. Un 711 gaida 710, lai pabeigtu darījumu.
Un tajā pat ir norādīts, kurā rindā notiek strupceļi. Un šeit tas sāk kļūt dīvaini.
Tagad mēs atjauninām no 80 uz 80.
Un šeit sākas strupceļi. 710 gaida atbildi no 711, un 711 gaida 710. Un tas labi nebeigsies. Un no tā nav izejas. Un viņi gaidīs atbildi viens no otra.
Un tas tikai sāks visu aizkavēt. Un mēs to nevēlamies.
Un Postgres ir veidi, kā pamanīt, kad tas notiek. Un, kad tas notiek, tiek parādīta šī kļūda. Un no tā ir skaidrs, ka šāds un tāds process gaida SHARE LOCK no cita procesa, t.i., kuru bloķē 711 process. Un tas process gaidīja, kad uz tāda un tāda darījuma ID tiks piešķirts SHARE LOCK, un tika bloķēts ar tādu un tādu procesu. Tāpēc šeit ir strupceļa situācija.
Vai pastāv trīsvirzienu strupceļi? Vai tas ir iespējams? Jā.
Mēs ievadām šos skaitļus tabulā. Mēs mainām 40 uz 40, veicam bloķēšanu.
Mēs mainām 60 uz 61, 80 uz 81.
Un tad mainam 80 un tad bums!
Un 714. tagad gaida 715. 716. gaida 715. numuru. Un tur neko nevar darīt.
Šeit vairs nav divi cilvēki, šeit jau ir trīs cilvēki. Es gribu kaut ko no tevis, šis vēlas kaut ko no trešās personas, un trešais vēlas kaut ko no manis. Un mēs nonākam trīspusējo gaidīšanas režīmā, jo mēs visi gaidām, kad otrs pabeigs to, kas viņam jādara.
Un Postgres zina, kurā rindā tas notiek. Tādējādi tiks parādīts šāds ziņojums, kas parāda, ka jums ir problēma, kurā trīs ieejas bloķē viena otru. Un šeit nav nekādu ierobežojumu. Tas var būt gadījumā, ja 20 ieraksti bloķē viens otru.
Nākamā problēma ir serializējama.
Ja īpaša serializējama slēdzene.
Un mēs atgriežamies pie 719. Tā izvade ir diezgan normāla.
Un jūs varat noklikšķināt, lai padarītu darījumu no sērijveida.
Un jūs saprotat, ka jums tagad ir cita veida SA slēdzene - tas nozīmē, ka var serializēt.
Un tāpēc mums ir jauna veida slēdzene ar nosaukumu SARieadLock, kas ir sērijas slēdzene un ļauj ievadīt seriālos.
Un arī jūs varat ievietot unikālus indeksus.
Šajā tabulā mums ir unikāli indeksi.
Tātad, ja es šeit ievietoju skaitli 2, tātad man ir 2. Bet pašā augšā es ievietoju vēl 2. Un jūs varat redzēt, ka 721 ir ekskluzīva slēdzene. Bet tagad 722 gaida, kad 721 pabeigs savu darbību, jo nevar ievietot 2, kamēr nezina, kas notiks ar 721.
Un, ja mēs veicam apakšdarījumu.
Šeit mums ir 723.
Un, ja mēs saglabājam punktu un pēc tam to atjauninām, mēs iegūstam jaunu darījuma ID. Tas ir vēl viens uzvedības modelis, kas jums jāapzinās. Ja mēs to atgriežam, darījuma ID pazūd. 724 aizbrauc. Bet tagad mums ir 725.
Tātad, ko es šeit cenšos darīt? Es mēģinu parādīt piemērus neparastām slēdzenēm, kuras jūs varētu atrast: neatkarīgi no tā, vai tās ir serializējamās slēdzenes vai SAVEPOINT, tie ir dažāda veida slēdzenes, kas tiks parādītas slēdzeņu tabulā.
Šī ir nepārprotamu (precīzu) slēdzeņu izveide, kurām ir pg_advisory_lock.
Un jūs redzat, ka bloķēšanas veids ir norādīts kā ieteicošs. Un šeit sarkanā krāsā ir rakstīts “konsultants”. Un jūs varat vienlaikus bloķēt šādi, izmantojot pg_advisory_unlock.
Un nobeigumā es vēlos jums parādīt vēl vienu prātu satraucošu lietu. Es izveidošu citu skatu. Bet es pievienošos tabulai pg_locks ar tabulu pg_stat_activity. Un kāpēc es vēlos to darīt? Jo tas ļaus man apskatīt un redzēt visas pašreizējās sesijas un precīzi redzēt, kāda veida slēdzenes viņi gaida. Un tas ir diezgan interesanti, kad mēs saliekam kopā bloķēšanas tabulu un vaicājumu tabulu.
Un šeit mēs izveidojam pg_stat_view.
Un mēs atjauninām rindu pa vienam. Un šeit mēs redzam 724. Un tad mēs atjauninām savu rindu uz trīs. Un ko tu te tagad redzi? Tie ir pieprasījumi, t.i., jūs redzat visu pieprasījumu sarakstu, kas ir norādīti kreisajā kolonnā. Un tad labajā pusē var redzēt aizsprostojumus un to, ko tie rada. Un tas jums var būt skaidrāks, lai jums nebūtu katru reizi jāatgriežas katrā sesijā un jāpārbauda, vai jums tai ir jāpievienojas. Viņi to dara mūsu vietā.
Vēl viena ļoti noderīga funkcija ir pg_blocking_pids
. Jūs droši vien nekad neesat par viņu dzirdējuši. Ko viņa dara? Tas ļauj mums pateikt, ka šai sesijai 11740, kādus konkrētus procesa ID tā gaida. Un var redzēt, ka 11740 gaida 724. Un 724 ir pašā augšā. Un 11306 ir jūsu procesa ID. Būtībā šī funkcija iet caur jūsu bloķēšanas tabulu. Un es zinu, ka tas ir nedaudz sarežģīti, bet jums izdodas to saprast. Būtībā šī funkcija iet caur šo bloķēšanas tabulu un mēģina atrast, kur šim procesa ID tiek piešķirts slēdzenēm, kuras tā gaida. Un tas arī mēģina noskaidrot, kurš procesa ID ir procesam, kas gaida bloķēšanu. Tātad jūs varat palaist šo funkciju pg_blocking_pids
.
Un tas var būt ļoti noderīgi. Mēs to pievienojām tikai 9.6 versijā, tāpēc šī funkcija ir tikai 5 gadus veca, taču tā ir ļoti, ļoti noderīga. Un tas pats attiecas uz otro pieprasījumu. Tas parāda tieši to, kas mums jāredz.
Par to es gribēju ar jums parunāt. Un, kā jau gaidīju, mēs iztērējām visu savu laiku, jo bija tik daudz slaidu. Un slaidi ir pieejami lejupielādei. Es vēlētos pateikties jums, ka esat šeit. Esmu pārliecināts, ka jums patiks pārējā konferences daļa, liels paldies!
Jautājumi:
Piemēram, ja es mēģinu atjaunināt rindas un otrajā sesijā tiek mēģināts dzēst visu tabulu. Cik saprotu, vajadzētu būt tādam kā nolūka bloķēšanai. Vai Postgresā ir kas tāds?
Atgriezīsimies pašā sākumā. Varat atcerēties, ka, veicot jebko, piemēram, veicot SELECT, mēs izsniedzam AccessShareLock. Un tas novērš galda nokrišanu. Tātad, ja, piemēram, vēlaties atjaunināt tabulas rindu vai dzēst rindu, kāds nevarēs dzēst visu tabulu vienlaikus, jo jūs turat šo AccessShareLock pāri visai tabulai un rindai. Kad esat pabeidzis, viņi var to izdzēst. Bet, kamēr jūs tur tieši kaut ko mainīsit, viņi to nevarēs izdarīt.
Darīsim to vēlreiz. Pāriesim pie dzēšanas piemēra. Un jūs redzat, kā rindā virs visa galda ir ekskluzīva slēdzene.
Tas izskatīsies kā ekskluzīva slēdzene, vai ne?
Jā, tā izskatās. Es saprotu, par ko jūs runājat. Jūs sakāt, ka, ja es veicu SELECT, tad man ir ShareExclusive un tad es to izveidoju par ekskluzīvu rindu, vai tā kļūst par problēmu? Bet pārsteidzoši tas nerada problēmas. Tas izskatās kā bloķēšanas pakāpes palielināšana, taču būtībā man ir bloķēšana, kas novērš dzēšanu. Un tagad, kad es padarīšu šo slēdzeni jaudīgāku, tas joprojām novērš dzēšanu. Tāpēc nav tā, ka es eju augšā. Tas nozīmē, ka tas neļāva tam notikt arī tad, kad tas bija zemākā līmenī, tāpēc, kad es paaugstinu tā līmeni, tas joprojām neļauj dzēst tabulu.
Es saprotu, par ko jūs runājat. Šeit nav slēdzenes eskalācijas gadījuma, kad jūs mēģināt atteikties no vienas slēdzenes, lai ieviestu spēcīgāku. Šeit tas tikai palielina šo profilaksi visā pasaulē, tāpēc tas neizraisa nekādus konfliktus. Bet tas ir labs jautājums. Liels paldies, ka uzdevāt šo jautājumu!
Kas mums jādara, lai izvairītos no strupceļa situācijas, kad mums ir daudz sesiju, liels lietotāju skaits?
Postgres automātiski pamana strupceļa situācijas. Un tas automātiski izdzēsīs vienu no sesijām. Vienīgais veids, kā izvairīties no bloķēšanas, ir bloķēt cilvēkus tādā pašā secībā. Tātad, kad paskatās uz jūsu pieteikumu, bieži vien strupceļa iemesls... Iedomāsimies, ka es vēlos bloķēt divas dažādas lietas. Viena lietojumprogramma bloķē 1. tabulu, cita lietojumprogramma bloķē 2. tabulu un pēc tam 1. tabulu. Vienkāršākais veids, kā izvairīties no strupceļa, ir apskatīt savu lietojumprogrammu un mēģināt pārliecināties, ka bloķēšana notiek tādā pašā secībā visās lietojumprogrammās. Un tas parasti novērš 80% problēmu, jo visādi cilvēki raksta šos pieteikumus. Un, ja jūs tos bloķējat tādā pašā secībā, jūs nesaskarsities ar strupceļu.
Liels paldies par sniegumu! Jūs runājāt par vakuuma pilnu un, ja pareizi saprotu, vakuuma pilna izkropļo ierakstu secību atsevišķā krātuvē, tāpēc viņi saglabā pašreizējos ierakstus nemainīgus. Kāpēc vakuums pilnībā aizņem ekskluzīvu bloķēšanas piekļuvi un kāpēc tas ir pretrunā ar rakstīšanas darbībām?
Tas ir labs jautājums. Iemesls ir tāds, ka pilns vakuums aizņem galdu. Un mēs būtībā veidojam jaunu tabulas versiju. Un galds būs jauns. Izrādās, šī būs pilnīgi jauna tabulas versija. Un problēma ir tā, ka, kad mēs to darām, mēs nevēlamies, lai cilvēki to lasītu, jo mums ir nepieciešams, lai viņi redzētu jauno tabulu. Un tā tas ir saistīts ar iepriekšējo jautājumu. Ja mēs varētu lasīt vienlaikus, mēs nevarētu to pārvietot un novirzīt cilvēkus uz jaunu galdu. Mums būtu jāgaida, līdz visi pabeigs lasīt šo tabulu, un tāpēc tā būtībā ir ekskluzīva situācija.
Mēs vienkārši sakām, ka bloķējam no sākuma, jo zinām, ka pašās beigās mums būs nepieciešama ekskluzīva slēdzene, lai visus pārvietotu uz jauno eksemplāru. Tātad mēs varam to atrisināt. Un mēs to darām šādi ar vienlaicīgu indeksēšanu. Bet to izdarīt ir daudz grūtāk. Un tas lielā mērā attiecas uz jūsu iepriekšējo jautājumu par ekskluzīvo slēdzeni.
Vai Postgres ir iespējams pievienot bloķēšanas taimautu? Oracle es varu, piemēram, uzrakstīt "select to update" un pagaidīt 50 sekundes pirms atjaunināšanas. Tas bija labs pieteikumam. Bet Postgresā man vai nu tas jādara uzreiz un vispār nav jāgaida, vai arī jāpagaida līdz brīdim.
Jā, jūs varat izvēlēties taimautu savām slēdzenēm un slēdzenēm. Varat arī izdot komandu nekādā veidā, kas... ja nevarēsiet uzreiz iegūt bloķēšanu. Tāpēc vai nu bloķēšanas taimauts, vai kaut kas cits, kas ļaus jums to izdarīt. Tas netiek darīts sintaktiskā līmenī. Tas tiek darīts kā mainīgais serverī. Dažreiz to nevar izmantot.
Vai varat atvērt 75. slaidu?
Jā.
Un mans jautājums ir šāds. Kāpēc abi atjaunināšanas procesi gaida 703?
Un tas ir lielisks jautājums. Starp citu, es nesaprotu, kāpēc Postgres to dara. Bet, kad tika izveidots 703, tas gaidīja 702. Un, kad parādās 704 un 705, šķiet, ka viņi nezina, ko viņi gaida, jo tur vēl nekā nav. Un Postgres to dara šādi: kad nevarat dabūt slēdzeni, tas raksta "Kāda jēga tevi apstrādāt?", jo jūs jau kādu gaidāt. Tāpēc mēs vienkārši ļausim tam karāties gaisā, tas to nemaz neatjauninās. Bet kas šeit notika? Tiklīdz 702 pabeidza procesu un 703 saņēma bloķēšanu, sistēma atgriezās atpakaļ. Un viņa teica, ka tagad mums ir divi cilvēki, kas gaida. Un tad atjaunināsim tos kopā. Un norādīsim, ka abi ir gaidībās.
Es nezinu, kāpēc Postgres to dara. Bet ir problēma, ko sauc par f…. Man šķiet, ka tas nav termins krievu valodā. Tas ir tad, kad visi gaida vienu pili, pat ja ir 20 iestādes, kas gaida pili. Un pēkšņi viņi visi pamostas vienlaicīgi. Un visi sāk mēģināt reaģēt. Bet sistēma dara tā, ka visi gaida 703. Jo viņi visi gaida, un mēs tūlīt visus saliksim rindā. Un, ja parādās kāds cits jauns pieprasījums, kas tika ģenerēts pēc šī, piemēram, 707, tad atkal būs tukšums.
Un man liekas, ka tas tiek darīts, lai varētu teikt, ka šajā posmā 702. gaida 703. un visiem tiem, kas nāks pēc tam, šajā laukā nebūs nekāda ieraksta. Bet, tiklīdz pirmais viesmīlis aiziet, visi tie, kas tobrīd gaidīja pirms atjauninājuma, saņem to pašu žetonu. Un tāpēc es domāju, ka tas tiek darīts, lai mēs varētu apstrādāt kārtībā, lai tie būtu pareizi pasūtīti.
Es vienmēr uz to skatījos kā uz diezgan dīvainu parādību. Tā kā šeit, piemēram, mēs tos nemaz neuzskaitām. Bet man šķiet, ka katru reizi, kad dodam jaunu slēdzeni, mēs skatāmies uz visiem tiem, kas ir gaidīšanas procesā. Tad mēs tos visus sarindojam. Un tad jebkurš jauns, kas ienāk, nonāk rindā tikai tad, kad ir pabeigta nākamās personas apstrāde. Ļoti labs jautājums. Liels paldies par jūsu jautājumu!
Man šķiet, ka daudz loģiskāk ir, kad 705 sagaida 704.
Bet problēma šeit ir šāda. Tehniski jūs varat pamodināt vienu vai otru. Un tā mēs pamodināsim vienu vai otru. Bet kas notiek sistēmā? Jūs varat redzēt, kā 703 pašā augšpusē ir bloķējis savu darījuma ID. Šādi darbojas Postgres. Un 703 bloķē savs darījuma ID, tāpēc, ja kāds vēlas gaidīt, tad gaidīs 703. Un būtībā 703 pabeidz. Un tikai pēc tā pabeigšanas kāds no procesiem pamostas. Un mēs nezinām, kāds tieši būs šis process. Tad visu apstrādājam pakāpeniski. Bet nav skaidrs, kurš process tiek pamodināts pirmais, jo tas varētu būt jebkurš no šiem procesiem. Būtībā mums bija plānotājs, kas teica, ka tagad varam pamodināt jebkuru no šiem procesiem. Mēs vienkārši izvēlamies vienu pēc nejaušības principa. Tāpēc abi ir jāatzīmē, jo mēs varam pamodināt jebkuru no viņiem.
Un problēma ir tā, ka mums ir CP-bezgalība. Un tāpēc ir diezgan iespējams, ka mēs varam pamodināt vēlāko. Un, ja, piemēram, pamodināsim vēlāko, tad gaidīsim to, kurš tikko saņēma bloku, tāpēc nenosakām, kurš tieši tiks pamodināts pirmais. Mēs vienkārši izveidojam šādu situāciju, un sistēma tos pamodinās nejaušā secībā.
Ir
Avots: www.habr.com