Bruce Momjianın 2020-ci il "Postgres Kilid Menecerinin Kilidinin Açılması" çıxışının transkripsiyası.
(Qeyd: Bütün SQL sorğularını bu linkdəki slaydlardan əldə edə bilərsiniz:
Salam! Burada yenidən Rusiyada olmaq çox gözəldir. Keçən il gələ bilmədiyim üçün üzr istəyirəm, amma bu il İvanla mənim böyük planlarımız var. Ümid edirəm ki, burada daha tez-tez olacağam. Rusiyaya gəlməyi sevirəm. Tyumen, Tverə səfər edəcəyəm. Mən çox şadam ki, bu şəhərləri ziyarət edə biləcəyəm.
Mənim adım Bruce Momjiandır. Mən EnterpriseDB-də işləyirəm və 23 ildən çoxdur Postgres ilə işləyirəm. Mən ABŞ-ın Filadelfiya şəhərində yaşayıram. İldə təxminən 90 gün səyahət edirəm. Mən isə 40-a yaxın konfransda iştirak edirəm. mənim
Postgres ilə işləməyə başlamazdan əvvəl müəllim, professor idim. Və mən çox şadam ki, indi sizə deyəcəklərimi deyə bilərəm. Bu mənim ən maraqlı təqdimatlarımdan biridir. Və bu təqdimat 110 slayddan ibarətdir. Biz sadə şeylərdən danışmağa başlayacağıq və hesabatın sonunda bu, getdikcə daha da mürəkkəbləşəcək və kifayət qədər mürəkkəbləşəcək.
Bu olduqca xoşagəlməz söhbətdir. Bloklama ən populyar mövzu deyil. İstəyirik ki, haradasa yox olsun. Bu diş həkiminə getmək kimidir.
- Kilidləmə verilənlər bazası üzərində işləyən və eyni anda birdən çox prosesi işləyən bir çox insan üçün problemdir. Onların bloklanması lazımdır. Yəni bu gün sizə bloklama haqqında əsas biliklər verəcəyəm.
- Əməliyyat ID-ləri. Bu təqdimatın olduqca darıxdırıcı hissəsidir, lakin onları başa düşmək lazımdır.
- Sonra, bloklama növləri haqqında danışacağıq. Bu, kifayət qədər mexaniki bir hissədir.
- Və sonra bloklama ilə bağlı bəzi nümunələr verəcəyik. Və başa düşmək olduqca çətin olacaq.
Bloklama haqqında danışaq.
Terminologiyamız kifayət qədər mürəkkəbdir. Bu keçidin haradan gəldiyini neçəniz bilirsiniz? İki nəfər. Bu Colossal Cave Adventure adlı oyundandır. Məncə, 80-ci illərdə mətn əsaslı kompüter oyunu idi. Orada mağaraya, labirintə girmək lazım idi və mətn dəyişdi, lakin məzmun hər dəfə təxminən eyni idi. Bu oyunu belə xatırlayıram.
Və burada biz Oracle-dan bizə gələn kilidlərin adını görürük. Biz onlardan istifadə edirik.
Burada məni çaşdıran terminləri görürük. Məsələn, SHARE UPDATE EKXLUSIVE. Sonrakı RAW EKXLÜZİVİ PAYLAŞIN. Açığı, bu adlar çox da aydın deyil. Onları daha ətraflı nəzərdən keçirməyə çalışacağıq. Bəzilərində ayırmaq mənasını verən “pay” sözü var. Bəzilərində "eksklüziv" sözü var - eksklüziv. Bəzilərində bu sözlərin hər ikisi var. Mən bu kilidlərin necə işlədiyindən başlamaq istərdim.
Və "giriş" sözü də çox vacibdir. Və "sətir" sözləri - bir xətt. Yəni giriş paylanması, sıra paylanması.
Postgres-də başa düşülməli olan başqa bir problem, təəssüf ki, çıxışımda əhatə edə bilməyəcəyim, MVCC-dir. Saytımda bu mövzuda ayrıca təqdimatım var. Və bu təqdimatın çətin olduğunu düşünürsənsə, MVCC yəqin ki, mənim ən çətinimdir. Əgər maraqlanırsınızsa, saytda baxa bilərsiniz. Videonu izləyə bilərsiniz.
Anlamalı olduğumuz başqa bir şey əməliyyat identifikatorlarıdır. Bir çox əməliyyatlar unikal identifikatorlar olmadan işləyə bilməz. Və burada əməliyyatın nə olduğuna dair bir izahatımız var. Postgres iki əməliyyat nömrələmə sisteminə malikdir. Bilirəm ki, bu, çox gözəl bir həll deyil.
Həm də unutmayın ki, slaydları oxumaq olduqca çətin olacaq, buna görə də qırmızı ilə vurğulananlara diqqət yetirmək lazımdır.
baxırıq. Əməliyyat nömrəsi qırmızı rənglə vurğulanır. Burada SELECT pg_back funksiyası göstərilir. O, mənim əməliyyatımı və həmin əməliyyatın identifikatorunu qaytarır.
Daha bir şey, əgər bu təqdimatı bəyənirsinizsə və onu verilənlər bazanızda işə salmaq istəyirsinizsə, o zaman çəhrayı rənglə vurğulanmış bu linki izləyə və bu təqdimat üçün SQL-i yükləyə bilərsiniz. Və siz sadəcə onu PSQL-də işlədə bilərsiniz və bütün təqdimat heç vaxt ekranınızda görünəcək. İçərisində çiçəklər olmayacaq, amma heç olmasa onu görə bilərik.
Bu halda biz əməliyyat identifikatorunu görürük. Bu ona təyin etdiyimiz nömrədir. Postgres-də virtual əməliyyat identifikatoru adlanan başqa bir əməliyyat ID növü var
Və biz bunu başa düşməliyik. Bu çox vacibdir, əks halda Postgres-də kilidləməni başa düşə bilməyəcəyik.
Virtual tranzaksiya identifikatoru sabit dəyərləri ehtiva etməyən bir əməliyyat identifikatorudur. Məsələn, SELECT əmrini işlədirsəm, o zaman çox güman ki, verilənlər bazasını dəyişməyəcəyəm, heç nəyi kilidləməyəcəyəm. Beləliklə, biz sadə SELECT işlətdikdə, biz bu əməliyyata daimi ID vermirik. Orada ona yalnız virtual şəxsiyyət vəsiqəsi veririk.
Və bu, Postgres-in işini yaxşılaşdırır, təmizləmə qabiliyyətini yaxşılaşdırır, ona görə də virtual əməliyyat identifikatoru iki rəqəmdən ibarətdir. Slashdan əvvəlki ilk nömrə arxa uç identifikatorudur. Sağda isə sadəcə bir sayğac görürük.
Buna görə sorğu işlətsəm, arxa uç ID-nin 2 olduğunu söyləyir.
Əgər mən bir sıra belə əməliyyatlar həyata keçirsəm, onda görürük ki, sorğunu hər dəfə yerinə yetirəndə sayğac artır. Məsələn, sorğunu 2/10, 2/11, 2/12 və s. çalıştırdığımda.
Nəzərə alın ki, burada iki sütun var. Solda virtual əməliyyat ID-ni görürük - 2/12. Sağda isə daimi əməliyyat identifikatorumuz var. Və bu sahə boşdur. Və bu əməliyyat verilənlər bazasını dəyişdirmir. Ona görə də mən ona daimi əməliyyat identifikatoru təyin etmirəm.
Təhlil əmrini ((ANALİZ) yerinə yetirən kimi eyni sorğu mənə daimi əməliyyat ID-si verir. Görün necə dəyişmişik. Əvvəllər bu vəsiqə məndə yox idi, indi var.
Beləliklə, burada başqa bir sorğu, başqa bir əməliyyat var. Virtual əməliyyat nömrəsi 2/13-dir. Mən daimi əməliyyat identifikatoru istəsəm, sorğunu yerinə yetirəndə onu alacağam.
Beləliklə, bir daha. Bizdə virtual əməliyyat ID və daimi əməliyyat ID var. Postgresin davranışını başa düşmək üçün bu nöqtəni götürün.
Üçüncü hissəyə keçirik. Burada yalnız Postgres-də müxtəlif növ kilidləri gəzəcəyik. Çox maraqlı deyil. Son hissə daha maraqlı olacaq. Ancaq əsas şeyləri nəzərə almalıyıq, çünki əks halda bundan sonra nə olacağını başa düşməyəcəyik.
Bu bölmədən keçəcəyik, hər bir bloklama növünə baxacağıq. Mən sizə onların necə quraşdırıldığına, necə işlədiyinə dair nümunələr göstərəcəyəm, Postgres-də bloklamanın necə işlədiyini görmək üçün istifadə edə biləcəyiniz bəzi sorğuları göstərəcəyəm.
Sorğu yaratmaq və Postgres-də nə baş verdiyini görmək üçün sorğunu sistem görünüşünə verməliyik. Bu halda, pg_lock qırmızı rənglə vurğulanır. pg_lock, Postgres-də hansı kilidlərin hazırda istifadə olunduğunu bildirən sistem cədvəlidir.
Bununla belə, pg_lock-u sizə göstərmək mənim üçün çox çətindir, çünki bu, olduqca mürəkkəbdir. Beləliklə, pg_locks göstərən bir görünüş yaratdım. Həm də bu, mənim üçün daha yaxşı başa düşməyə imkan verən bəzi işlər görür. Yəni mənim kilidlərimi, öz sessiyamı və s. istisna edir. Bu, sadəcə standart SQL-dir və baş verənləri daha yaxşı göstərməyə imkan verir.
Başqa bir problem, bu görünüşün çox geniş olmasıdır, ona görə də ikincisini yaratmalıyam - lockview2.
Və mənə cədvəldən daha çox sütun göstərir. Və mənə qalan sütunları göstərən başqa bir. Bu olduqca mürəkkəbdir, ona görə də onu mümkün qədər sadə şəkildə təqdim etməyə çalışdım.
Beləliklə, biz Lockdemo adlı bir cədvəl yaratdıq. Biz orada bir xətt yaratdıq. Bu bizim nümunə cədvəlimizdir. Sizə bloklama nümunələrini göstərmək üçün bölmələr yaradacağıq.
Beləliklə, bir sıra, bir sütun. Birinci növ kilid ACCESS SHARE adlanır. Bu ən az məhdudlaşdırıcı blokdur. Bu o deməkdir ki, digər qıfıllarla praktiki olaraq ziddiyyət təşkil etmir.
Və əgər biz açıq şəkildə kilidi təyin etmək istəyiriksə, biz "kilid masası" əmrini icra edirik. Və açıq şəkildə bloklayacaq, yəni ACCESS SHARE rejimində biz kilid masasını işlədirik. Və əgər mən PSQL-i arxa planda başlasam, o zaman birinci seansımdan ikinci seansa bu şəkildə başlayıram. Yəni mən burada nə edəcəm? Mən başqa seansa gedirəm və ona deyirəm ki, "bu sorğunun kilid görünüşünü mənə göstər". Və burada bu masada AccessShareLock var. Bu, sadəcə xahiş etdiyim şeydir. Və deyir ki, kilid təyin olunub. Çox sadə.
Bundan əlavə, ikinci sütuna baxsaq, orada heç bir şey yoxdur. Onlar boşdur.
Əgər mən "SEÇ" əmrini yerinə yetirsəm, bu, AccessShareLock sorğusunun gizli (açıq) yoludur. Beləliklə, mən cədvəlimi buraxıram və sorğu işlədirəm və sorğu birdən çox sətir qaytarır. Və sətirlərin birində AccessShareLock-u görürük. Beləliklə, SELECT masada AccessShareLock-u çağırır. Və demək olar ki, heç bir şeylə ziddiyyət təşkil etmir, çünki bu, aşağı səviyyəli bir kiliddir.
SELECT işlətsəm və üç fərqli cədvəlim olsa nə olacaq? Əvvəllər yalnız bir cədvəl işlədirdim, indi üçü işlədirəm: pg_class, pg_namespace və pg_attribute.
İndi isə sorğuya baxanda 9 cədvəldə XNUMX AccessShareLocks görürəm. Niyə? Üç cədvəl mavi rənglə vurğulanır: pg_attribute, pg_class, pg_namespace. Lakin siz həmçinin görə bilərsiniz ki, bu cədvəllər vasitəsilə müəyyən edilən bütün indekslərdə AccessShareLock da var.
Və bu, praktiki olaraq başqaları ilə ziddiyyət təşkil etməyən bir blokdur. Və yalnız biz onu seçərkən masadan düşməyimizə mane olur. Məntiqlidir. Yəni cədvəli seçsək, həmin anda yox olur, deməli, bu səhvdir AccessShare bizə "mən işləyərkən bu cədvəli silməyin" deyən aşağı səviyyəli kiliddir.. Əsasən, onun etdiyi hər şey budur.
ROW SHARE - Bu kilid bir az fərqlidir.
Bir nümunə götürək. Hər cərgəni ayrı-ayrılıqda kilidləmək üçün SƏTİR PAYLAŞIMI SEÇİN. Beləliklə, biz onlara baxarkən heç kim onları silə və ya dəyişə bilməz.
Beləliklə, SHARE LOCK nə edir? SELECT üçün əməliyyat ID-nin 681 olduğunu görürük. Və maraqlıdır. Burada nə olub? İlk dəfə "Kilid" sahəsində nömrəni görürük. Biz əməliyyat identifikatorunu götürürük və o, onu eksklüziv rejimdə blokladığını deyir. Bütün bunlar, cədvəlin bir yerində texniki cəhətdən kilidlənmiş bir sıram olduğunu söyləyir. Amma dəqiq harada olduğunu demir. Buna bir az sonra daha ətraflı baxacağıq.
Burada deyirik ki, kilid bizim tərəfimizdən istifadə olunur.
Beləliklə, eksklüziv kilid açıq şəkildə (açıq şəkildə) eksklüziv olduğunu söyləyir. Həm də bu cədvəldə bir sıra silsəniz, gördüyünüz kimi, belə olur.
SHARE EXCLUSIVE daha uzun kiliddir.
Bu (ANALYZE) istifadə olunacaq analizator əmridir.
SHARE LOCK - Paylaşım rejimində açıq şəkildə kilidləyə bilərsiniz.
Siz həmçinin unikal indeks yarada bilərsiniz. Və orada onların bir hissəsi olan SHARE LOCK-u görə bilərsiniz. Və masanı kilidləyir və üzərinə SHARE LOCK kilidi qoyur.
Cədvəldəki standart SHARE LOCK o deməkdir ki, digər insanlar cədvəli oxuya bilər, lakin heç kim onu dəyişdirə bilməz. Unikal indeks yaradanda da məhz belə olur.
Əgər mən unikal eyni zamanda indeks yaratsam, o zaman fərqli növ kilidə sahib olacağam, çünki yadda saxlayın ki, eyni vaxtda indekslərdən istifadə kilid tələbini azaldır. Və əgər mən normal kiliddən, normal indeksdən istifadə etsəm, o zaman onun yaradılması zamanı cədvəlin indeksinə yazılmasının qarşısını almışam. Əgər mən eyni vaxtda indeksdən istifadə edirəmsə, başqa növ kiliddən istifadə etməliyəm.
SHARE ROW EKSKLÜZİV - yenə də açıq şəkildə (açıq şəkildə) təyin edilə bilər.
Və ya bir qayda yarada bilərik, yəni onun istifadə olunacağı konkret halı götürə bilərik.
EKSKLÜZİV kilid o deməkdir ki, başqa heç kim masanı dəyişə bilməz.
Burada müxtəlif növ kilidləri görürük.
ACCESS EXCLUSIVE, məsələn, kilidləmə əmridir. Məsələn, etsəniz CLUSTER table
, onda bu o demək olacaq ki, orada heç kim yaza bilməyəcək. Və yalnız cədvəlin özünü deyil, indeksləri də kilidləyir.
Bu, ACCESS EKSKLÜZİV kilidinin ikinci səhifəsidir, burada onun cədvəldə xüsusi olaraq nəyi bağladığını görürük. Fərdi masa sıralarını kilidləyir, bu da kifayət qədər maraqlıdır.
Vermək istədiyim əsas məlumatlar bunlardır. Biz kilidlərdən, əməliyyat identifikatorlarından danışdıq, virtual əməliyyat identifikatorlarından, daimi əməliyyat identifikatorlarından danışdıq.
İndi biz bloklama nümunələrindən keçəcəyik. Bu, ən maraqlı hissədir. Çox maraqlı hallar görəcəyik. Və bu təqdimatdakı məqsədim Postgres hər şeyi bloklamağa çalışarkən əslində nə etdiyi barədə sizə daha yaxşı fikir verməkdir. Mənə elə gəlir ki, o, ayrı-ayrı hissələrin qarşısını almaqda çox bacarıqlıdır.
Bəzi konkret nümunələrə baxaq.
Cədvəllərdən və masa başına bir sıradan başlayacağıq. Mən bir şey daxil edərkən, masada ExclusiveLock, Transaction ID və ExclusiveLock alıram.
Daha iki cərgə daxil etsəm nə olar? İndi masamızda üç sıra var. Mən bir sıra daxil etdim və bunu bir çıxış olaraq aldım. Və daha iki cərgə daxil etsəm, burada qəribə nə var? Burada qəribəlik var, çünki mən bu cədvələ üç cərgə əlavə etmişəm, amma kilid masasında hələ də iki sıra var. Və bu, əslində Postgresin əsas davranışıdır.
Bir çox insanlar hesab edir ki, verilənlər bazasında 100 sətir kilidləyirsinizsə, onda 100 kilid girişi yaratmalı olacaqsınız. Bir anda 1 sətri bloklasam, o zaman 000 belə sorğuya ehtiyacım olacaq. Mən bloklamaq üçün bir milyon və ya milyard lazımdırsa. Amma bunu etsək, çox yaxşı nəticə verməyəcək. Hər bir fərdi sıra üçün bloklama qeydləri yaradan bir sistemdən istifadə etmisinizsə, bunun mürəkkəb olduğunu görə bilərsiniz. Çünki siz dərhal kilid masasını təyin etməlisiniz, bu da daşmaq olar, lakin Postgres bunu etmir.
Və bu slaydda çox vacibdir ki, o, MVCC daxilində fərdi xətləri bloklayan başqa bir sistemin olduğunu açıq şəkildə nümayiş etdirir. Beləliklə, siz milyardlarla cərgəni kilidlədiyiniz zaman Postgres milyard ayrı kilid təlimatı yaratmır. Və bu performans üçün çox yaxşıdır.
Bəs yeniləmə haqqında? İndi seriyanı yeniləyirəm və bir anda iki fərqli əməliyyat etdiyini görə bilərsiniz. Eyni zamanda masanı bağladı, amma indeksi də kilidlədi. Və o, indeksi bağlamalı idi, çünki bu cədvəldə unikal məhdudiyyətlər var. Və biz əmin olmaq istəyirik ki, heç kim onu dəyişdirmir, ona görə də onu bloklayırıq.
İki sıra yeniləmək istəsəm nə olar? Və onun da eyni cür davrandığını görürük. Biz iki dəfə çox yeniləmə edirik, lakin eyni sayda bloklama xətləri.
Postgres-in bunu necə etdiyi ilə maraqlanırsınızsa, Postgres-in dəyişdirdiyi bu sətirləri daxili olaraq necə qeyd etdiyini öyrənmək üçün MVCC-dəki danışıqlarıma qulaq asmalısınız. Və Postgres-in bunu etmək üsulu var, lakin o, bunu masanın kilidləmə səviyyəsində etmir, daha aşağı və daha səmərəli səviyyədə edir.
Nəyisə silmək istəsəm nə olar? Məsələn, bir sıra silsəm və hələ də kiliddə iki girişim var və hamısını silmək istəsəm də, onlar hələ də oradadır.
Və məsələn, mən 1 sətir daxil etmək istəyirəm, sonra ya silmək, ya da 000 sətir əlavə etmək, sonra əlavə etdiyim və ya dəyişdirdiyim fərdi sətirlər burada qeyd olunmur. Onlar sətrin özündə daha aşağı səviyyədə yazılır. Və MVCC söhbəti zamanı mən bu barədə ətraflı danışdım. Lakin siz kilidləri təhlil edərkən çox vacibdir ki, sizdə masa səviyyəli kilid var və burada fərdi sətirlərin necə yazıldığını görə bilmirsiniz.
Bəs açıq bloklama haqqında?
"Yenilə" düyməsini klikləsəm, iki sıra kilidlənəcək. Hamısını seçib "hər yerdə yenilə" düyməsini klikləsəm, hələ də iki kilid qeydim var.
Biz hər bir fərdi sıra üçün ayrıca qeydlər yaratmırıq. Çünki o zaman performans azalır, çox ola bilər. Və özümüzü xoşagəlməz vəziyyətə sala bilərik.
Eyni şey, əgər paylaşsaq, hər şeyi 30 dəfə edə bilərik.
Cədvəlimizi bərpa edirik, hər şeyi silirik, sonra yenidən bir sıra daxil edirik.
Postgres-də gördüyünüz başqa bir davranış növü çox yaxşı bilinən və arzu olunan davranışdır ki, yeniləmə və ya seçim edə bilərsiniz. Və eyni zamanda bunu edə bilərsiniz. Və seçin yeniləməni maneə törətmir və eyni şeyi əks istiqamətdə. Oxucuya deyirik ki, yazıçını bloklama, yazıçı da oxucunu əngəlləməyib.
Mən sizə bunun bir nümunəsini göstərəcəyəm. İndi seçim edəcəm. Sonra INSERT edəcəyik. Və sonra görə bilərsiniz - 694. Bu əlavəni edən əməliyyatın ID-sini görə bilərsiniz. Və bu belə işləyir.
İndi backend ID-yə baxsam, o oldu - 695.
Və görürəm ki, cədvəlimdə 695 görünür.
Mən burada belə yeniləsəm, başqa bir hal alıram. Bu halda, 695 eksklüziv kiliddir və yeniləmə eyni davranışa malikdir, lakin onlar arasında heç bir ziddiyyət yoxdur, bu olduqca qeyri-adidir.
Üstdə ShareLock, aşağıda isə ExclusiveLock olduğunu görə bilərsiniz. Və hər iki əməliyyat uğurlu oldu.
Bunun necə baş verdiyini anlamaq üçün MVCC-dəki çıxışımı dinləməlisiniz. Ancaq bu, eyni vaxtda edə biləcəyinizi, yəni eyni vaxtda SEÇİM və YENİLƏNMƏni həyata keçirə biləcəyinizi göstərən bir nümunədir.
Sıfırlayaq və yenidən bir əməliyyat edək.
Eyni cərgədə eyni anda iki yeniləməni işə salmağa çalışsanız, o, bloklanacaq. Yadınızdadırsa, mən demişdim ki, oxucu yazıçını deyil, oxucunun yazıçısını bloklayır, bir yazıçı digər yazıçını bloklayır. Yəni iki nəfərin eyni sıranı eyni anda yeniləməsinə icazə verə bilmərik. Onlardan biri bitənə qədər gözləmək lazımdır.
Bunu göstərmək üçün mən Lockdemo cədvəlinə baxacağam. Və bir sıraya baxacağıq. Əməliyyat üçün 698.
Biz onu 2-yə yüksəltmişik. 699 ilk yeniləmədir. Və o, uğurlu alındı və ya gözlənilən əməliyyatdadır, bizim törətməyimizi və ya ləğv etməyimizi gözləyir.
Ancaq başqa bir şeyə baxın - 2/51 bizim ilk əməliyyatımız, ilk seansımızdır. 3/112 yuxarıdan gələn və bu dəyəri 3-ə dəyişdirən ikinci sorğudur. Əgər fikir versəniz, yuxarıdakı 699-dur. Amma 3/112 kilid vermədi. Lock_mode sütunu onun gözlədiyini bildirir. O, 699 gözləyir. 699-un harada olduğuna baxsanız, o, daha yüksəkdir. Və ilk seans nə etdi? O, öz əməliyyat ID-sində eksklüziv kilid yaratdı. Postgres bunu belə edir. Öz əməliyyat ID-sini bloklayır. Və kiminsə törətməsini və ya ləğv etməsini gözləmək istəyirsinizsə, o zaman gözlənilən əməliyyat varkən gözləməli olacaqsınız. Beləliklə, qəribə bir xətt görə bilərik.
Yenidən baxaq. Solda biz emal ID-mizi görürük. İkinci sütunda virtual əməliyyat identifikatorumuzu, üçüncüdə isə lock_type-ni görürük. Bu nə deməkdir? Əslində, o, əməliyyat ID-ni blokladığını deyir. Ancaq diqqət yetirin ki, bütün sətirlərdə aşağıda əlaqə yazılıb. Beləliklə, stolun üstündə iki növ qıfıl var. Əlaqə kilidi var. Həmçinin, biz özümüz bağlayacağınız bir tranzakid kilidi var, bu, birinci cərgədə və ya 699-un fəaliyyətini bitirməsini gözlədiyimiz tranzakidin olduğu ən aşağı hissədə baş verənlərdir.
Burada nə baş verdiyini görürəm. Və burada iki şey eyni anda baş verir. Siz birinci cərgədə özünü kilidləyən əməliyyat ID kilidinə baxırsınız. Və insanları gözləmək üçün özünü bloklayır.
6-cı sətirə baxsanız, birinci ilə eyni girişdir. Beləliklə, 699 əməliyyatı bloklanır. 700 də öz-özünə kilidlənir. Və sonra alt cərgədə 699-un fəaliyyətini tamamlamasını gözlədiyimizi görəcəksiniz.
Və lock_type-də siz nömrələri görürsünüz.
0/10 olduğunu görə bilərsiniz. Və bu, səhifə nömrəsi və həmçinin həmin sıranın ofsetidir.
Yenilədiyimiz zaman 0/11-in nə olduğunu görürsünüz.
Amma əslində 0/10-dur, çünki bu əməliyyatla bağlı gözlənti var. Bizim təsdiqləmək üçün gözlədiyim sıranın bu olduğunu görmək imkanımız var.
Biz bunu təsdiq etdikdən və öhdəliyi sıxdıqdan sonra yeniləmə tamamlandıqda, yenidən əldə etdiyimiz şey budur. Tranzaksiya 700 yeganə qıfıldır, başqasını gözləmir, çünki törədilmişdir. Sadəcə əməliyyatın tamamlanmasını gözləyir. 699 bitdikdən sonra başqa heç nə gözləmirik. İndi 700 əməliyyatı deyir ki, hər şey qaydasındadır, bütün icazə verilən cədvəllərdə lazım olan bütün kilidlərə malikdir.
Və hər şeyi daha da çətinləşdirmək üçün, bu dəfə bizə bir iyerarxiya təqdim edəcək başqa bir görünüş yaradırıq. Bu xahişi başa düşməyinizi gözləmirəm. Ancaq bu, bizə nə baş verdiyini daha aydın şəkildə göstərəcək.
Bu, daha bir bölməsi olan rekursiv görünüşdür. Və sonra hər şeyi yenidən bir araya gətirir. Gəlin bundan istifadə edək.
Eyni vaxtda üç yeniləmə etsək və sıranın indi üç olduğunu desək nə olar? Və 3-ü 4-ə dəyişəcəyik.
Və burada biz 4 görürük. Və əməliyyat ID 702.
Və sonra 4-ü 5-ə dəyişdirəcəyəm. Və 5-i 6-ya, 6-nı 7-yə dəyişdirəcəyəm. Mən bu bir əməliyyatın tamamlanmasını gözləmək üçün bir neçə insanı sıraya düzürəm.
Və hər şey aydın olur. Birinci sıra nədir? Bu, 702-dir. Bu, ilkin olaraq bu dəyəri təyin edən əməliyyat ID-sidir. Verilmiş sütununda nəyim var? işarələrim var f
. Bunlar mənim yeniləmələrimdir ki, (5, 6, 7) təsdiq edilə bilməz, çünki biz əməliyyat ID 702-nin müddətinin bitməsini gözləyirik. Orada bir əməliyyat ID kilidimiz var. Və 5 əməliyyat kilidi ID çıxır.
704-ə, 705-ə baxsanız, hələ orada heç nə yazılmayıb, çünki onlar hələ nə baş verdiyini bilmirlər. Sadəcə yazırlar ki, nə baş verdiyindən xəbərləri yoxdur. Və onlar sadəcə yuxuya gedəcəklər, çünki kiminsə bitməsini gözləyirlər və sıranı dəyişmək mümkün olanda oyanacaqlar.
Göründüyü kimi budur. Aydın məsələdir ki, onların hamısı 12-ci sıranı gözləyir.
Burada gördüyümüz budur. Budur 0/12.
Beləliklə, ilk əməliyyat təsdiqləndikdən sonra burada iyerarxiyanın necə işlədiyini görə bilərsiniz. Və indi hər şey aydındır. Hamısı təmiz olur. Və əslində hələ də gözləyirlər.
Budur nə baş verir. 702 öhdəlik götürür. İndi 703 bu sıra kilidini alır və sonra 704 703-ün yerinə yetirilməsini gözləməyə başlayır. 705 də bunu gözləyir. Bütün bunlar başa çatdıqdan sonra özlərini təmizləyirlər. Və qeyd etmək istərdim ki, hamı növbəyə düzülür. Və bu, hamının ilk maşını gözlədiyi tıxac vəziyyətinə çox bənzəyir. Birinci maşın dayandı və hamı uzun növbəyə düzülür. Sonra hərəkət edir, sonra növbəti maşın qabağa çıxıb blokunu ala bilər və s.
Əgər sizə kifayət qədər çətin görünmürdüsə, indi sizinlə çıxılmaz vəziyyətlərdən danışacağıq. Bilmirəm hansınız bunları yaşayıb. Bu verilənlər bazası sistemlərində kifayət qədər ümumi problemdir. Ancaq çıxılmaz vəziyyətlər bir seansın nəyisə etmək üçün digər sessiyanı gözlədiyi zamandır. Və o anda başqa bir seans nəsə etmək üçün ilk sessiyanı gözləyir.
Məsələn, İvan desə: "Mənə bir şey ver" və mən deyirəm: "Xeyr, yalnız mənə başqa bir şey versən, sənə verərəm". O da deyir ki, yox, sən verməsən sənə verməyəcəyəm. Və biz çıxılmaz vəziyyətə düşürük. Əminəm ki, İvan bunu etməyəcək, amma başa düşürsən ki, bizdə iki nəfər nəyisə istəyir və onlar başqası onlara istədiklərini verənə qədər onu verməyə hazır deyillər. Və heç bir həll yoxdur.
Və əslində, verilənlər bazanız bunu aşkar etməlidir. Və sonra sessiyalardan birini silmək və ya bağlamaq lazımdır, çünki əks halda onlar əbədi olaraq orada qalacaqlar. Biz bunu verilənlər bazalarında görürük, əməliyyat sistemlərində görürük. Bizdə paralel proseslərin olduğu bütün yerlərdə bu baş verə bilər.
Və biz indi iki çıxılmaz vəziyyətə salacağıq. 50 və 80 qoyacağıq.Birinci sırada 50-dən 50-yə qədər yeniləyəcəyəm.710 əməliyyat nömrəsini alacağam.
Və sonra 80-i 81-ə, 50-ni isə 51-ə dəyişəcəyəm.
Və bu necə görünəcək. Beləliklə, 710-da sıra kilidi var və 711 təsdiqini gözləyir. Yenilənəndə bunu gördük. 710 - seriyamızın sahibidir. Və 711 əməliyyatı tamamlamaq üçün 710 gözləyir.
Hətta hansı cərgədə dalana dirəndiyimizi deyir. Və burada qəribələşməyə başlayır.
İndi biz 80-dən 80-ə yeniləyirik.
Və burada dalana dirənişlər başlayır. 710 711-dən cavab gözləyir, 711 isə 710-u gözləyir. Bunun sonu yaxşı olmayacaq. Və bundan çıxış yolu yoxdur. Və bir-birindən cavab gözləyəcəklər.
Və yalnız hər şeyi gecikdirməyə başlayır. Və biz bunu istəmirik.
Postgresin bunun nə vaxt baş verdiyini fərq etmək yolları var. Və bu baş verdikdə, bu səhvi alırsınız. Və buradan aydın olur ki, filan proses başqa bir prosesdən, yəni 711 prosesi tərəfindən bloklanan SHARE LOCK gözləyir. Və o proses filan əməliyyat ID-yə SHARE LOCK verilməsini və filan proses tərəfindən bloklanmasını gözləyirdi. Buna görə də ölü bloklanma vəziyyəti var.
Üç tərəfli çıxılmaz vəziyyətlər varmı? Bu mümkündür? Bəli.
Bu nömrələri cədvələ daxil edirik. 40-dan 40-a dəyişirik, kilid düzəldirik.
60-ı 61-ə, 80-ni 81-ə dəyişin.
Və sonra biz 80 dəyişirik və sonra bum!
Və 714 indi 715 gözləyir. 716 715 gözləyir. Və bununla bağlı ediləcək heç nə yoxdur.
Artıq iki nəfər yox, üç nəfər var. Mən səndən bir şey istəyirəm, bu üçüncü şəxsdən, üçüncü şəxs isə məndən bir şey istəyir. Və biz üç yollu bir gözləmə ilə sona çatırıq, çünki hamımız digər insanın etməli olduğu işi tamamlamasını gözləyirik.
Postgres bunun hansı cərgədə baş verdiyini bilir. Və beləliklə, üç girişin bir-birini blokladığı bir probleminiz olduğunu göstərən aşağıdakı mesajı verəcəkdir. Və heç bir məhdudiyyət yoxdur. Bu, 20 girişin bir-birini blokladığı hal ola bilər.
Növbəti məsələ seriallaşdırıla bilər.
Xüsusi serializable kilid varsa.
Və 719-a qayıdırıq. Onun tamamilə normal problemi var.
Siz serializable-dən əməliyyat etmək üçün təkan verə bilərsiniz.
Və başa düşürsünüz ki, indi fərqli bir SA bloklama növü var - bu, seriallaşdırıla bilən deməkdir.
Beləliklə, SARieadLock adlı yeni növ kilidimiz var, bu, seriyalı kiliddir və seriya nömrələrini daxil etməyə imkan verir.
Həm də unikal indekslər əlavə edə bilərsiniz.
Bu cədvəldə unikal indekslərimiz var.
Beləliklə, əgər mən burada 2 rəqəmini qoysam, buna görə də məndə 2 var. Amma ən yuxarıda başqa 2 qoyuram. Və 721-in eksklüziv kilidi olduğunu görə bilərsiniz. Ancaq indi 722, 721-in işini tamamlamasını gözləyir, çünki 2-ə nə olacağını bilənə qədər 721-ni daxil edə bilməz.
Və əgər biz subtransaction etsək.
Burada 723 var.
Və biz nöqtəni saxlasaq və sonra onu yeniləsək, yeni bir əməliyyat identifikatoru alırıq. Bu, xəbərdar olmanız lazım olan başqa bir davranışdır. Bunu qaytarsaq, əməliyyat ID-si getdi. 724 gedir. Amma indi bizdə 725 var.
Və mən burada nə etməyə çalışıram? Mən sizə tapa biləcəyiniz qeyri-adi kilidlərin nümunələrini göstərməyə çalışıram: istər seriallaşdırıla bilən kilidlər, istərsə də SAVEPOINT kilidləri, bunlar kilid cədvəlində görünəcək müxtəlif növ kilidlərdir.
Bu, pg_advisory_lock olan açıq (açıq) kilidlərin yaradılmasıdır.
Və görə bilərsiniz ki, kilid növü burada məsləhət kimi qeyd olunub. Və burada qırmızı ilə "məsləhət" yazılır. Siz pg_advisory_unlock ilə eyni vaxtda blok edə bilərsiniz.
Və sonda sizə daha bir ağıla salan şeyi göstərmək istərdim. Başqa bir görünüş yaradacağam. Amma pg_locks cədvəlinə pg_stat_activity cədvəli ilə qoşulacam. Və niyə bunu etmək istəyirəm? Çünki bu, mənə bütün cari seanslara baxmağa və görməyə və onların hansı növ kilidləri gözlədiyini görməyə imkan verəcək. Kilid masası və sorğu masasını bir araya gətirdikdə kifayət qədər maraqlıdır.
Və burada pg_stat_view yaradırıq.
Və sıranı bir-bir yeniləyirik. Və burada biz 724-ü görürük. Və sonra sıramızı üçə yeniləyirik. Və indi burada nə görürsən? Bunlar sorğulardır, yəni siz sol sütunda sadalanan sorğuların bütün siyahısını görürsünüz. Və sonra sağ tərəfdə kilidləri və onların yaratdığını görə bilərsiniz. Və bu, sizin üçün daha başa düşülən ola bilər ki, hər dəfə hər seansa qayıdıb ona qoşulmağa ehtiyacınız olub-olmamağınıza baxmaq məcburiyyətində qalmayasınız. Bunu bizim üçün edirlər.
Çox faydalı olan başqa bir xüsusiyyət pg_blocking_pids
. Yəqin ki, onun haqqında heç eşitməmisiniz. O nə edir? Bu, 11740 seansı üçün hansı proses identifikatorlarını gözlədiyini söyləməyə imkan verir. Və görürsən ki, 11740 724 gözləyir. Və 724 ən yuxarıdadır. 11306 isə proses identifikatorunuzdur. Əslində, bu funksiya kilid masanızın üstündən keçir. Və bilirəm ki, bu bir az mürəkkəbdir, amma siz fikirləşirsiniz. Əslində, bu funksiya bu kilidləmə cədvəlindən keçir və gözlədiyi kilidləri nəzərə alaraq bu proses ID-nin harada olduğunu tapmağa çalışır. Həm də kilidi gözləyən prosesin hansı proses ID-yə sahib olduğunu anlamağa çalışır. Beləliklə, bu funksiyanı işlədə bilərsiniz pg_blocking_pids
.
Və bu çox faydalıdır. Biz bunu yalnız 9.6 versiyasından bəri əlavə etdik, ona görə də bu funksiyanın cəmi 5 yaşı var, lakin çox, çox faydalıdır. Eyni şey ikinci sorğuya da aiddir. Görməmiz lazım olanı dəqiq göstərir.
Sizinlə danışmaq istədiyim budur. Və gözlədiyim kimi, slaydlar çox olduğu üçün bütün vaxtımızı sərf etdik. Və slaydlar yükləmək üçün mövcuddur. Burada olduğunuz üçün sizə təşəkkür etmək istərdim. Əminəm ki, konfransın qalan hissəsindən zövq alacaqsınız, çox sağ olun!
Suallar:
Məsələn, mən satırları yeniləməyə çalışsam və ikinci seans bütün cədvəli silməyə çalışarsa. Anladığım qədər, niyyət kilidi kimi bir şey olmalıdır. Postgresdə belə bir şey varmı?
Ən başlanğıca qayıdırıq. Xatırlaya bilərsiniz ki, siz hər hansı bir iş görəndə, məsələn, SEÇİM etdikdə, biz AccessShareLock veririk. Və masanın düşməsinin qarşısını alır. Beləliklə, əgər siz, məsələn, cədvəldə bir sıra yeniləmək və ya cərgəni silmək istəyirsinizsə, o zaman kimsə eyni anda bütün cədvəli silə bilməz, çünki siz bu AccessShareLock-u bütün cədvəlin üzərində və cərgənin üstündə saxlayırsınız. Və işiniz bitdikdən sonra onu silə bilərlər. Amma nə qədər ki, sən birbaşa orada nəyisə dəyişsən, onlar bunu edə bilməyəcəklər.
Yenidən edək. Silmə nümunəsinə keçək. Və cərgənin bütün masa üzərində necə eksklüziv kilidi olduğunu görürsünüz.
Bu, eksklüziv bir kilid kimi görünəcək, elə deyilmi?
Bəli, belə görünür. Nə danışdığını başa düşürəm. Siz deyirsiniz ki, mən SEÇİM etsəm, ShareExclusive-ə sahib oluram və sonra bunu Sıra Eksklüziv vəziyyətinə qoyuram, bu, problemə çevrilirmi? Ancaq təəccüblüdür ki, bu problem yaratmır. Bu, kilidin dərəcəsini artırmaq kimidir, amma mahiyyətcə mənim onun silinməsinə mane olan bir kilidim var. İndi, mən bu kilidi daha güclü etdikdə, o, hələ də silinmənin qarşısını alır. Deməli, mən yuxarı qalxmaq kimi deyiləm. Yəni, aşağı səviyyədə olanda da qarşısını aldı, ona görə də onu qaldırdığımda yenə də masanın düşməsinin qarşısını alır.
Nə danışdığını başa düşürəm. Daha güclü bir blok təqdim etmək üçün bir blokdan imtina etməyə çalışdığınız bloklanma dərəcəsinin artırılması halı yoxdur. Burada sadəcə olaraq hər yerdə bu qaçınmanı artırır, ona görə də heç bir münaqişəyə səbəb olmur. Amma yaxşı sualdır. Soruşduğunuz üçün çox sağ olun!
Çoxlu seanslarımız, çox sayda istifadəçimiz olduqda dalana dirənməmək üçün nə etməliyik?
Postgres çıxılmaz vəziyyətləri avtomatik olaraq qeyd edir. Və seanslardan birini avtomatik siləcək. Çıxılmaz vəziyyətdən qaçmağın yeganə yolu insanları eyni qaydada bloklamaqdır. Beləliklə, ərizənizə baxdığınız zaman, tez-tez kilidlərin səbəbi olur... Tutaq ki, mən iki fərqli şeyi bloklamaq istəyirəm. Bir proqram 1-ci cədvəli, digəri isə cədvəl 2-ni, sonra isə cədvəl 1-i kilidləyir. Və çıxılmaz vəziyyətdən qaçmağın ən asan yolu tətbiqinizə baxmaq və kilidin bütün proqramlarda eyni ardıcıllıqla baş verdiyinə əmin olmaqdır. Və bu adətən problemlərin 80%-ni aradan qaldırır, çünki bu proqramları hər cür insan yazır. Əgər siz onları eyni qaydada bloklasanız, o zaman dalana dirənməzsiniz.
Performansınız üçün çox sağ olun! Siz vakuum dolu haqqında danışdınız və əgər mən düzgün başa düşsəm, vakuum tam ayrı bir mağazada qeydlərin sırasını pozur, ona görə də cari qeydləri dəyişməz saxlayır. Niyə vakuum tam eksklüziv kilid girişi alır və niyə yazma əməliyyatları ilə ziddiyyət təşkil edir?
Bu yaxşı sualdır. Səbəb, vakuumun dolu bir masa götürməsidir. Və biz əslində cədvəlin yeni versiyasını yaradırıq. Və masa yeni olacaq. Məlum oldu ki, bu, cədvəlin tamamilə yeni versiyası olacaq. Problem ondadır ki, biz bunu edəndə insanların onu oxumasını istəmirik, çünki onların yeni cədvəli görmələrini istəyirik. Və bu, əvvəlki sualla əlaqələndirilir. Eyni zamanda oxuya bilsəydik, o zaman onu köçürə və insanları yeni cədvələ yönəldə bilməzdik. Hər kəsin bu cədvəli oxuyub bitirməsini gözləmək məcburiyyətində qalacağıq və buna görə də mahiyyət etibarı ilə bu, eksklüziv vəziyyətdir.
Biz sadəcə əvvəldən kilidlədiyimizi deyirik, çünki hamını yeni nüsxəyə köçürmək üçün ən sonunda eksklüziv kilidə ehtiyacımız olacağını bilirik. Beləliklə, biz bunu potensial olaraq həll edə bilərik. Biz bunu eyni vaxtda indeksləşdirmə ilə belə edirik. Ancaq bunu etmək daha çətindir. Və bu, eksklüziv kilidlə bağlı əvvəlki sualınıza çox güclü şəkildə aiddir.
Postgres-də kilidləmə vaxtı əlavə etmək mümkündürmü? Oracle-da mən, məsələn, "güncelləmək üçün seçin" yaza və yeniləmədən əvvəl 50 saniyə gözləyə bilərəm. Tətbiq üçün yaxşı oldu. Ancaq Postgres-də mən bunu dərhal etməliyəm və ümumiyyətlə gözləməməliyəm, ya da bir müddət gözləyin.
Bəli, siz kilidlərinizin, kilidlərinizin vaxt aşımını seçə bilərsiniz. Siz həmçinin heç bir şəkildə əmr verə bilərsiniz, bu da ... kilidi dərhal ala bilmirsinizsə. Buna görə də, ya kilidləmə müddəti, ya da bunu etməyə imkan verəcək başqa bir şey. Bu sintaktik səviyyədə edilmir. Bu serverdə dəyişən kimi edilir. Bəzən istifadə etmək olmur.
75-ci slaydı aça bilərsinizmi?
Bəli.
Və növbəti sualımdır. Niyə hər iki yeniləmə prosesi 703-ü gözləyir?
Və bu əla sualdır. Yeri gəlmişkən, Postgresin niyə belə etdiyini başa düşmürəm. Lakin 703 yaradılanda o, 702-ni gözləyirdi. 704 və 705 görünəndə isə, deyəsən, nə gözlədiklərini bilmirlər, çünki orada hələ heç nə yoxdur. Postgres isə bunu belə edir: kilid ala bilməyəndə “Səni emal etməyin nə mənası var?” deyir, çünki artıq kimisə gözləyirsən. Ona görə də havada qalsın, onu heç yeniləməsin. Amma burada nə baş verdi? 702 prosesi başa vuran və 703-ü kilidini alan kimi sistem geri qayıtdı. Və dedi ki, indi iki nəfər gözləyirik. Və sonra gəlin onları birlikdə yeniləyək. Və hər ikisinin gözlənilən olduğunu bildiririk.
Postgresin niyə belə etdiyini bilmirəm. Amma f... adlı bir problem var. Mənə elə gəlir ki, bu, rus dilində termin deyil. Bu, qalanı gözləyən 20 instansiya olsa belə, hər kəsin bir qala gözlədiyi zamandır. Və birdən hamısı eyni vaxtda oyanır. Və hər kəs reaksiya verməyə başlayır. Amma sistem elə edir ki, hamı 703-ü gözləyir. Bundan sonra yaranan başqa bir yeni sorğu, məsələn, 707 görünsə, yenidən boşluq olacaq.
Mənə elə gəlir ki, bu, indiki mərhələdə 702-nin 703-ü gözlədiyini və ondan sonra gələnlərin hamısının bu sahəyə heç bir girişinin olmayacağını söyləmək üçün edilir. Ancaq ilk ofisiant ayrılan kimi və yeniləmədən əvvəl o anda gözləyənlərin hamısı eyni nişanı alır. Və mənə elə gəlir ki, bu, biz qaydada emal etmək üçün edilir ki, onlar düzgün sifariş olunsun.
Mən həmişə buna olduqca qəribə bir fenomen kimi baxmışam. Çünki burada, məsələn, onlar ümumiyyətlə siyahıya alınmayıb. Amma, mənə elə gəlir ki, biz hər dəfə yeni qıfıl verəndə gözləmə prosesində olanların hamısına baxırıq. Sonra hamısını sıralayırıq. Və sonra gələn hər hansı yeni yalnız növbəti şəxs emalını bitirdikdə növbəyə alınır. Çox yaxşı sual. Sualınıza görə çox sağ olun!
Mənə 705 704 gözlədikdə daha məntiqli görünür.
Ancaq burada problem aşağıdakılardan ibarətdir. Texniki olaraq, ya birini, ya da birini oyandıra bilərsiniz. Və beləliklə, bir və ya digərini oyanırıq. Bəs sistemin işində nə baş verir? Ən yuxarıda 703-ün öz əməliyyat ID-sini necə blokladığını görə bilərsiniz. Postgres belə işləyir. Və 703 öz əməliyyat identifikatoru ilə bloklanır, ona görə də kimsə gözləmək istəsə, 703-ü gözləyəcək. Və əslində 703 tamamlayır. Və yalnız başa çatdıqdan sonra proseslərdən biri oyanır. Və bunun necə bir proses olacağını bilmirik. Sonra hər şeyi tədricən emal edirik. Amma hansı prosesin əvvəl oyandığı bəlli deyil, çünki bu, bu proseslərdən hər hansı biri ola bilər. Əsasən, indi bu proseslərdən hər hansı birini oyada biləcəyimizi söyləyən bir planlaşdırıcımız var idi. Sadəcə təsadüfi birini seçirik. Ona görə də onların hər ikisini qeyd etmək lazımdır, çünki biz onlardan hər hansı birini oyada bilərik.
Problem ondadır ki, bizdə CP-sonsuzluğu var. Və buna görə də, çox güman ki, sonrakını oyandıra bilərik. Və əgər, məsələn, daha sonra oyansaq, o zaman kilidi yenicə qəbul edəni gözləyəcəyik, buna görə də ilk olaraq kimin oyanacağını müəyyən etmirik. Biz məhz belə bir vəziyyət yaradırıq və sistem onları təsadüfi şəkildə oyatacaq.
Yoxdur
Mənbə: www.habr.com