PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Hesabatda imkan verən bəzi yanaşmalar təqdim olunur gündə milyonlarla sorğu olduqda SQL sorğularının performansına nəzarət edin, və yüzlərlə idarə olunan PostgreSQL serverləri var.

Hansı texniki həllər bizə belə bir həcmdə məlumatı səmərəli şəkildə emal etməyə imkan verir və bu, adi bir tərtibatçının həyatını necə asanlaşdırır.


Kim maraqlanır xüsusi problemlərin təhlili və müxtəlif optimallaşdırma üsulları SQL sorğuları və PostgreSQL-də tipik DBA tapşırıqlarının həlli - siz də edə bilərsiniz məqalələr seriyasına baxın bu mövzuda.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)
Mənim adım Kirill Borovikov, təmsil edirəm "Tensor" şirkəti. Konkret olaraq şirkətimizdə verilənlər bazası ilə işləmək üzrə ixtisaslaşmışam.

Bu gün sizə tək bir sorğunun performansını "götürməyə" ehtiyac duymadığınız zaman, ancaq problemi kütləvi şəkildə həll etməyiniz üçün sorğuların optimallaşdırılması ilə necə məşğul olduğumuzu söyləyəcəyəm. Milyonlarla sorğu olduqda və bəzilərini tapmaq lazımdır həllinə yanaşmalar bu böyük problem.

Ümumiyyətlə, bir milyon müştərimiz üçün "Tensor" VLSI - bizim proqram: korporativ sosial şəbəkə, video kommunikasiya həlləri, daxili və xarici sənəd dövriyyəsi üçün, mühasibat uçotu və anbar üçün mühasibat sistemləri, ... Yəni, 100-dən çox müxtəlif daxili layihələrin mövcud olduğu inteqrasiya olunmuş biznesin idarə edilməsi üçün belə bir "meqakombin" .

Onların hamısının normal işləməsi və inkişaf etməsi üçün ölkə üzrə 10 inkişaf mərkəzimiz var, onların daha çox 1000 tərtibatçı.

Biz 2008-ci ildən PostgreSQL ilə işləyirik və emal etdiyimiz şeylərin böyük bir hissəsini topladıq - bunlar müştəri məlumatları, statistik, analitik, xarici informasiya sistemlərindən alınan məlumatlardır - 400 TB-dən çox. Yalnız "istehsalda" təxminən 250 server var və ümumilikdə nəzarət etdiyimiz 1000-ə yaxın verilənlər bazası serveri var.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

SQL deklarativ dildir. Siz bir şeyin "necə" işləməli olduğunu deyil, "nə" əldə etmək istədiyinizi təsvir edirsiniz. DBMS JOIN-i necə edəcəyini daha yaxşı bilir - cədvəllərinizi necə birləşdirmək, hansı şərtləri qoymaq, indeksdən nə keçəcək, nə olmayacaq ...

Bəzi DBMS göstərişləri qəbul edir: "Xeyr, bu iki cədvəli filan növbə ilə birləşdirin", lakin PostgreSQL necə olduğunu bilmir. Bu, aparıcı tərtibatçıların şüurlu mövqeyidir: "Tərtibatçılara bir növ göstərişlərdən istifadə etməyə icazə verməkdənsə, sorğu optimallaşdırıcısını bitirmək daha yaxşıdır."

Ancaq PostgreSQL-in "kənar"ın özünü idarə etməsinə icazə verməməsinə baxmayaraq, mükəmməl imkan verir gör içəridə nələr gedirSorğunuzu işlətdiyiniz zaman və harada problem yaranır.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Ümumiyyətlə, bir tərtibatçı [DBA-ya] adətən hansı klassik problemlərlə gəlir? “Budur, biz tələbi yerinə yetirdik və biz yavaşıq, hər şey asılır, bir şey olur ... Bir növ problem!

Səbəblər demək olar ki, həmişə eynidir:

  • səmərəsiz sorğu alqoritmi
    Tərtibatçı: "İndi onun üçün JOIN vasitəsilə SQL-də 10 cədvəlim var ..." - və onun şərtlərinin möcüzəvi şəkildə effektiv şəkildə "açılacağını" və hər şeyi tez əldə edəcəyini gözləyir. Amma möcüzələr baş vermir və belə dəyişkənliyə malik istənilən sistem (bir FROM-da 10 cədvəl) həmişə bir növ səhv verir. [məqalə]
  • köhnəlmiş statistika
    Bu an xüsusi olaraq PostgreSQL üçün çox aktualdır, serverə böyük bir verilənlər toplusunu “tökdüyünüz” zaman sorğu göndərin və o, sizi boşqabda “seks skan edir”. Çünki dünən orada 10 qeyd var idi, bu gün isə 10 milyondur, lakin PostgreSQL hələ bundan xəbərdar deyil və ona bu barədə məlumat vermək lazımdır. [məqalə]
  • resurslara "qoşmaq"
    Kifayət qədər disk, yaddaş və ya prosessorun özünün performansı olmayan zəif bir serverə böyük və ağır yüklənmiş verilənlər bazası yerləşdirirsiniz. Və hamısı budur ... Haradasa bir performans tavanı var, onun üstündən artıq tullanmaq mümkün deyil.
  • bloklama
    Çətin bir an, lakin onlar müxtəlif dəyişdirici sorğular üçün ən uyğundur (INSERT, UPDATE, DELETE) - bu ayrı bir böyük mövzudur.

Plan alın

… Və hər şey üçün biz plan lazımdır! Biz server daxilində nə baş verdiyini görməliyik.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

PostgreSQL üçün sorğu icra planı mətn təqdimatında sorğuların icrası alqoritmi ağacıdır. Məhz planlaşdırıcının təhlili nəticəsində ən effektiv alqoritm.

Hər bir ağac qovşağı bir əməliyyatdır: cədvəldən və ya indeksdən məlumat çıxarmaq, bitmap yaratmaq, iki cədvəli birləşdirmək, birləşdirmək, kəsişmək və ya seçimləri istisna etmək. Sorğunun yerinə yetirilməsi bu ağacın qovşaqlarından keçməkdir.

Sorğu planını əldə etmək üçün ən asan yol ifadəni yerinə yetirməkdir EXPLAIN. Bütün real atributları əldə etmək üçün, yəni əslində bazada bir sorğu yerinə yetirin - EXPLAIN (ANALYZE, BUFFERS) SELECT ....

Pis nöqtə: onu yerinə yetirdiyiniz zaman "burada və indi" baş verir, buna görə də yalnız yerli sazlama üçün uyğundur. Güclü məlumat dəyişiklikləri axını altında olan yüksək yüklənmiş serveri götürsəniz və görürsünüz: “Hey! Burada yavaş-yavaş çıxış etdikxia xahiş." Yarım saat, bir saat əvvəl - siz işləyərkən və jurnallardan bu sorğunu alarkən, onu serverə qaytararkən, bütün məlumat dəstiniz və statistikanız dəyişdi. Siz onu sazlamaq üçün işə salın - və o, sürətlə işləyir! Və "niyə", niyə başa düşə bilmirsən oldu yavaş-yavaş.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Sorğunun serverdə yerinə yetirildiyi anda nə olduğunu başa düşmək üçün ağıllı insanlar yazdılar auto_explain modulu. O, demək olar ki, bütün ən ümumi PostgreSQL paylamalarında mövcuddur və onu sadəcə konfiqurasiya faylında aktivləşdirmək olar.

Əgər o, hansısa sorğunun ona dediyiniz limitdən daha uzun sürdüyünü başa düşürsə, başa düşür Bu sorğunun planını "snapshot" edir və onları birlikdə jurnala yazır.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

İndi hər şey qaydasındadır, biz jurnala gedirik və orada görürük ... [mətnin ayaq örtüyü]. Ancaq bunun əla plan olması istisna olmaqla, bu barədə heç nə deyə bilmərik, çünki tamamlanması 11 ms çəkdi.

Hər şey yaxşı görünür - amma əslində nə baş verdiyi heç bir şey aydın deyil. Ümumi vaxtdan əlavə, biz xüsusi bir şey görmürük. Çünki belə bir "brat" düz mətnə ​​baxmaq ümumiyyətlə sevimlidir.

Ancaq aydın olmasa da, əlverişsiz olsa belə, daha fundamental problemlər var:

  • Düyün göstərir bütün alt ağacın resursları üzərində cəmi onun altında. Yəni, burada xüsusi olaraq bu İndeks Skanına nə qədər vaxt sərf olunduğunu öyrənmək sadəcə mümkün deyil - onun altında hansısa yuvalanmış vəziyyət varsa, mümkün deyil. İçəridə "uşaqlar" və şərti dəyişənlərin, CTE-nin olub olmadığını dinamik şəkildə görməliyik və bütün bunları "ağılda" çıxarmalıyıq.
  • İkinci nöqtə: qovşaqda göstərilən vaxtdır node icra müddəti. Bu node, məsələn, cədvəl qeydləri vasitəsilə bir dövr nəticəsində bir neçə dəfə yerinə yetirilibsə, plan bu node dövrlərinin sayını artırır. Ancaq atomun icra müddəti özü planda eyni olaraq qalır. Yəni, bu düyünün ümumilikdə nə qədər yerinə yetirildiyini başa düşmək üçün birini digəri ilə çoxaltmaq lazımdır - yenidən "ağılda".

Belə ssenarilərdə “Ən zəif halqa kimdir?” sualını anlayın. praktiki olaraq qeyri-realdır. Buna görə də, hətta "təlimatda" tərtibatçıların özləri belə yazır "Planı başa düşmək öyrənilməli bir sənətdir, təcrübədir...".

Amma bizim 1000 tərtibatçımız var və bu təcrübə onların hər birinə ötürülə bilməz. Mən, sən, o - bilirlər, amma orada kimsə - artıq yoxdur. Ola bilsin ki, öyrənəcək, ya yox, amma indi işləmək lazımdır - və bu təcrübəni haradan alacaqdı.

Plan vizualizasiyası

Ona görə də başa düşdük ki, bu problemlərin öhdəsindən gəlmək üçün bizə lazımdır planın yaxşı vizuallaşdırılması. [məqalə]

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Əvvəlcə "bazara" getdik - gəlin İnternetdə ümumiyyətlə mövcud olanlara baxaq.

Ancaq məlum oldu ki, az və ya çox inkişaf etmiş nisbətən "canlı" həllər çox azdır - sözün əsl mənasında bir şey: izah.depesz.com Hubert Lubaczewski tərəfindən. Sahənin girişində planın mətn təsvirini "qidalandırır", o, təhlil edilmiş məlumatları olan bir boşqab göstərir:

  • öz node emal vaxtı
  • bütün alt ağac üzərində ümumi vaxt
  • əldə edilmiş və statistik olaraq gözlənilən qeydlərin sayı
  • node gövdəsinin özü

Həmçinin, bu xidmət keçidlərin arxivini paylaşmaq imkanına malikdir. Planını ora atıb dedin: "Hey, Vasya, bura sənin üçün bir keçid var, orada nəsə səhvdir".

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Amma kiçik problemlər də var.

Birincisi, böyük miqdarda "kopyala-yapışdır". Günlükdən bir parça götürürsən, ora qoyursan, yenə də, yenə də.

İkincisi, oxunan məlumatların miqdarının təhlili yoxdur - çıxış edən eyni tamponlar EXPLAIN (ANALYZE, BUFFERS), biz bunu burada görmürük. Sadəcə olaraq, onları sökməyi, başa düşməyi və onlarla işləməyi bilmir. Çoxlu məlumat oxuduqda və diskdə və yaddaşdaxili keşdə düzgün parçalanmadığınızı anladığınız zaman bu məlumat çox vacibdir.

Üçüncü mənfi məqam bu layihənin çox zəif inkişafıdır. Öhdəliklər çox kiçikdir, hər altı ayda bir dəfə olsa yaxşıdır və kod Perldədir.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Ancaq bunların hamısı “lirika”dır, bununla da birtəhər yaşamaq olar, amma bizi bu xidmətdən uzaqlaşdıran bir şey var. Bunlar Ümumi Cədvəl İfadəsi (CTE) təhlil səhvləri və InitPlan/SubPlan kimi müxtəlif dinamik qovşaqlardır.

Bu şəklə inanırsınızsa, onda bizdə hər bir fərdi nodeun ümumi icra müddəti bütün sorğunun ümumi icra müddətindən böyükdür. Hər şey sadədir - bu CTE-nin yaranma vaxtı CTE Scan qovşağından çıxarılmamışdır. Buna görə də, artıq düzgün cavabı bilmirik, CTE skanının özü nə qədər çəkdi.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Sonra başa düşdük ki, özümüzü yazmağın vaxtı gəldi - ah! Hər bir tərtibatçı deyir: "İndi biz özümüzü yazacağıq, çox asan olacaq!"

Veb xidmətləri üçün xarakterik bir yığın götürdük: gözəl diaqramlar üçün Bootstrap və D3.js-də çəkilmiş Node.js + Express-də əsas. Və gözləntilərimiz özünü doğrultdu - 2 həftə ərzində ilk prototipi aldıq:

  • fərdi plan təhlili
    Yəni, indi PostgreSQL tərəfindən yaradılanlardan ümumilikdə istənilən planı təhlil edə bilərik.
  • dinamik qovşaqların düzgün təhlili - CTE Scan, InitPlan, SubPlan
  • buferlərin paylanması təhlili - məlumat səhifələrinin yaddaşdan oxunduğu yer, yerli keşdən, diskdən haradan oxunur
  • görmə qabiliyyəti əldə etdi
    Günlükdəki hər şeyi "qazmamaq" üçün deyil, dərhal şəkildəki "ən zəif əlaqəni" görmək üçün.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Bu şəkil kimi bir şey əldə etdik - dərhal sintaksis vurğulanması ilə. Ancaq adətən bizim tərtibatçılarımız artıq planın tam təqdimatı ilə deyil, daha qısa olan bir şeylə işləyirlər. Axı, biz artıq bütün nömrələri təhlil etdik və onları sola və sağa atdıq və ortada yalnız birinci sətir buraxdıq, bu hansı düyündür: CTE Scan, CTE nəsil və ya Seq Scan hansısa lövhəyə görə.

Bu adlandırdığımız qısaldılmış təmsildir plan şablonu.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Başqa nə rahat olardı? Ümumi vaxtın hansı payının hansı düyünə paylandığını görmək rahat olardı - və biz onu sadəcə yan tərəfə "yapışdırdıq" pasta grafiği.

Düyünə işarə edirik və görürük - belə çıxır ki, Seq Scan ümumi vaxtın dörddə birindən azını çəkdi, qalan 3/4 hissəsi isə CTE Scan tərəfindən götürüldü. Dəhşət! Bu, sorğularınızda aktiv istifadə etsəniz, CTE Scan-ın "atəş dərəcəsi" haqqında kiçik bir qeyddir. Onlar çox sürətli deyil - hətta adi bir masa taramasına da itirirlər. [məqalə] [məqalə]

Amma adətən belə diaqramlar daha maraqlı, daha mürəkkəb olur, biz dərhal seqmentə işarə etdikdə və biz, məsələn, bəzi Seq Scan-ın vaxtın yarısından çoxunu “yediyini” görürük. Üstəlik, içərisində bir növ Filtr var idi, üzərində çoxlu qeydlər atıldı ... Bu şəkli birbaşa tərtibatçıya atıb deyə bilərsiniz: “Vasya, burada hər şey pisdir! Anlayın, baxın - bir şey səhvdir!

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Təbii ki, "rake" olmadan edə bilməz.

Onların "addım atdıqları" ilk şey yuvarlaqlaşdırma problemi idi. Planda hər bir fərdi qovşağın qovşaq vaxtı 1 µs dəqiqliklə göstərilir. Və node dövrlərinin sayı, məsələn, 1000-dən çox olduqda - icra edildikdən sonra PostgreSQL "qədər" bölünür, sonra geriyə hesabladıqda, ümumi vaxtı "0.95 ms ilə 1.05 ms arasında" alırıq. Hesab mikrosaniyələrə çatdıqda, bu, hələ heç bir şey deyil, lakin artıq [milli] saniyəyə çatdıqda, "kim kimdən nə qədər istehlak etdi" planının qovşaqlarına uyğun olaraq resursları "açarkən" bu məlumatları nəzərə almalısınız.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Daha mürəkkəb olan ikinci məqam resursların (həmin buferlərin) dinamik qovşaqlar arasında paylanmasıdır. Prototip üçün ilk 2 həftə bizə daha 4 həftəyə başa gəldi.

Belə bir problemlə üzləşmək olduqca asandır - biz CTE edirik və guya orada bir şey oxuyuruq. Əslində, PostgreSQL “ağıllıdır” və orada birbaşa heç nə oxumayacaq. Sonra ondan ilk qeydi, yüz birincini isə eyni CTE-dən götürürük.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Biz plana baxırıq və başa düşürük - qəribədir ki, Seq Scan-da 3 bufer (məlumat səhifəsi), CTE Scan-da daha 1 və ikinci CTE Scan-da daha 2 "istehlak edilmiş" idi. Yəni, hər şeyi sadəcə yekunlaşdırsaq, 6 alırıq, ancaq planşetdən yalnız 3 oxuyuruq! CTE Scan heç bir yerdən heç nə oxumur, birbaşa proses yaddaşı ilə işləyir. Beləliklə, burada bir şey səhvdir!

Əslində belə çıxır ki, burada Seq Scan-dan tələb olunan bütün o 3 səhifə məlumat, əvvəlcə 1-i 1-ci CTE Scan, sonra isə 2-ci və daha 2-si ona oxunub, yəni cəmi 3 səhifə. səhifələr oxunmuş məlumatlar idi, 6 deyil.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Və bu şəkil bizi başa düşməyə vadar etdi ki, planın icrası artıq ağac deyil, sadəcə bir növ asiklik qrafikdir. Və biz bu diaqrama bənzər bir şey əldə etdik ki, "bir şeyin ümumiyyətlə haradan gəldiyini" başa düşək. Yəni burada biz pg_class-dan CTE yaratdıq və ondan iki dəfə soruşduq və demək olar ki, 2-ci dəfə istədikdə o, bizi filialın yanında apardı. Aydındır ki, 101-ci girişi oxumaq cədvəldəki 1-ci yazıdan qat-qat baha başa gəlir.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Bir müddət nəfəs aldıq. Dedi: “İndi, Neo, sən kunq-fu bilirsən! İndi təcrübəmiz sizin ekranınızdadır. İndi ondan istifadə edə bilərsiniz”. [məqalə]

Giriş Konsolidasiyası

1000 tərtibatçımız rahat nəfəs aldı. Ancaq başa düşdük ki, yalnız yüzlərlə "döyüş" serverimiz var və tərtibatçılar tərəfindən bütün bu "kopyala-yapışdır" heç də əlverişli deyil. Başa düşdük ki, onu özümüz toplamaq lazımdır.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Ümumiyyətlə, statistika toplaya bilən adi bir modul var, lakin onu da konfiqurasiyada aktivləşdirmək lazımdır - bu pg_stat_statements modulu. Amma o, bizə yaraşmırdı.

Birincisi, o, eyni verilənlər bazası daxilində müxtəlif sxemlər altında eyni sorğuları təyin edir müxtəlif Sorğuİdləri. Yəni ilk etsəniz SET search_path = '01'; SELECT * FROM user LIMIT 1;və sonra SET search_path = '02'; və eyni sorğu, onda bu modulun statistikasında müxtəlif qeydlər olacaq və mən sxemləri nəzərə almadan bu sorğu profili kontekstində xüsusi olaraq ümumi statistika toplaya bilməyəcəm.

Onu istifadə etməyimizə mane olan ikinci məqam - planların olmaması. Yəni plan yoxdur, sadəcə xahişin özü var. Nəyin yavaşladığını görürük, amma səbəbini anlamırıq. Və burada sürətlə dəyişən verilənlər toplusu probleminə qayıdırıq.

Və son an - "faktların" olmaması. Yəni, sorğunun icrasının konkret nümunəsinə müraciət edə bilməzsiniz - o, mövcud deyil, yalnız ümumiləşdirilmiş statistika var. Bununla işləmək mümkün olsa da, sadəcə çox çətindir.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Ona görə də “kopyala-yapışdır”la mübarizə aparmaq qərarına gəldik və yazmağa başladıq kollektor.

Kollektor SSH vasitəsilə bağlanır, sertifikatdan istifadə edərək verilənlər bazası ilə serverə təhlükəsiz əlaqəni “uzanır” tail -F log faylında ona "yapışır". Beləliklə, bu sessiyada bütün log faylının tam "güzgüsünü" alırıqserver tərəfindən yaradılan . Eyni zamanda, serverdəki yük minimaldır, çünki biz orada heç bir şeyi təhlil etmirik, sadəcə trafiki əks etdiririk.

Artıq Node.js-də interfeys yazmağa başladığımız üçün onun üzərinə kollektoru yazmağa davam etdik. Və bu texnologiya özünü doğrultdu, çünki log olan yüngül formatlaşdırılmış mətn verilənləri ilə işləmək üçün JavaScript-dən istifadə etmək çox rahatdır. Və Node.js infrastrukturunun özü də arxa plan platforması kimi şəbəkə əlaqələri və əslində bir növ məlumat axınları ilə işləməyi asan və rahat edir.

Müvafiq olaraq, biz iki əlaqəni "uzadırıq": birincisi, logun özünə "qulaq asmaq" və onu özümüzə aparmaq üçün, ikincisi isə vaxtaşırı bazadan soruşmaq üçün. "Ancaq jurnalda oid 123 olan planşetin bloklandığı ortaya çıxdı", lakin bu, tərtibatçı üçün heç nə demək deyil və bazadan "Hər halda OID = 123 nədir?" sualını vermək yaxşı olardı. Və buna görə də biz vaxtaşırı hələ bilmədiklərimizi bazadan soruşuruq.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

"Yalnız bir şeyi tərk etdiniz, filə bənzər bir arı növü var! .." 10 serveri izləmək istəyəndə bu sistemi inkişaf etdirməyə başladıq. Anlayışımızda ən kritik olan, həlli çətin olan bəzi problemlərin ortaya çıxdığı. Ancaq birinci rübdə monitorinq üçün yüz aldıq - sistem "girdi", hamı bunu istədi, hamı üçün əlverişlidir.

Bütün bunlar əlavə edilməlidir, məlumat axını böyükdür, aktivdir. Əslində, biz nəyə nəzarət edirik, nə ilə məşğul olacağımızı bilirik, ondan istifadə edirik. Biz həmçinin məlumat anbarı kimi PostgreSQL-dən istifadə edirik. Və heç bir şey ona operatordan daha sürətli məlumat "tökmək" deyil COPY Hələ yox.

Lakin sadəcə olaraq məlumatların “tökülməsi” bizim texnologiyamız deyil. Çünki yüz serverdə saniyədə təxminən 50k sorğunuz varsa, bu sizin üçün gündə 100-150GB loglar yaradacaq. Buna görə də bazanı diqqətlə "kəsməli" idik.

Birincisi, biz etdik günə bölmək, çünki, ümumiyyətlə, heç kəs günlər arasındakı korrelyasiya ilə maraqlanmır. Bu axşam tətbiqin yeni versiyasını - və artıq bəzi yeni statistik məlumatları təqdim etsəniz, dünən nə fərqi var.

İkincisi, öyrəndik (məcbur olduq) ilə yazmaq üçün çox tez COPY. Yəni təkcə yox COPYçünki daha sürətlidir INSERT, və hətta daha sürətli.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Üçüncü an - məcbur oldum imtina tetikleri, müvafiq olaraq, və Xarici Açarlardan. Yəni bizdə ümumiyyətlə referensial bütövlüyü yoxdur. Çünki üzərində bir cüt FK olan cədvəliniz varsa və siz verilənlər bazası strukturunda "burada FK tərəfindən istinad edilən log girişi var, məsələn, bir qrup girişə" deyirsinizsə, onu daxil edərkən PostgreSQL necə almaq və vicdanla icra etməkdən başqa heç nə qalmır SELECT 1 FROM master_fk1_table WHERE ... daxil etməyə çalışdığınız identifikatorla - sadəcə olaraq bu girişin orada olub-olmadığını yoxlamaq üçün, bu Xarici Açarı daxil etməklə "sındırmadığınızı" yoxlayın.

Hədəf cədvəlində və onun indekslərində bir qeyd əvəzinə, onun istinad etdiyi bütün cədvəllərdən oxuyuruq. Və buna ümumiyyətlə ehtiyacımız yoxdur - vəzifəmiz ən az yüklə mümkün qədər çox və mümkün qədər tez qeyd etməkdir. Beləliklə, FK - aşağı!

Növbəti nöqtə birləşmə və hashingdir. Əvvəlcə biz onları verilənlər bazasında tətbiq etdik - nəticədə, qeyd gələndə onu bir növ planşetdə etmək dərhal rahatdır. "plus bir" sağ tətikdə. Yaxşı, rahat, lakin eyni şəkildə pis - bir qeyd daxil edirsiniz, ancaq başqa bir cədvəldən başqa bir şey oxuyub yazmağa məcbur olursunuz. Üstəlik, təkcə oxumaq və yazmaq deyil, həm də hər dəfə bunu etmək.

İndi təsəvvür edin ki, müəyyən bir hostdan keçən sorğuların sayını hesabladığınız bir cədvəliniz var: +1, +1, +1, ..., +1. Və siz, prinsipcə, buna ehtiyacınız yoxdur - hər şey mümkündür kollektorda yaddaşda olan məbləğ və bir gedişdə bazaya göndərin +10.

Bəli, bir növ nasazlıq baş verərsə, məntiqi bütövlüyünüz "dağıla" bilər, lakin bu, demək olar ki, qeyri-real bir haldır - çünki normal bir serveriniz var, onun nəzarətçisində batareya var, əməliyyat jurnalınız var, fayl sisteminə daxil olun ... Ümumiyyətlə, buna dəyər deyil. Çəkdiyiniz xərc müqabilində tetikleyiciler/FK-ları işlətməklə əldə etdiyiniz performans itkisinə dəyməz.

Eyni şey hashing üçün də gedir. Müəyyən bir sorğu sizə uçur, siz bazada ondan müəyyən bir identifikator hesablayır, bazaya yazın və sonra hamıya söyləyin. Hər şey qaydasındadır, o vaxta qədər ki, səsyazma zamanı yanınıza onu özü yazmaq istəyən ikinci şəxs gəlsin - və sizdə tıxanma var və bu, artıq pisdir. Buna görə də, bəzi şəxsiyyət vəsiqələrinin nəslini müştəriyə ötürə bilsəniz (baza nisbətən), bunu etmək daha yaxşıdır.

MD5-dən mətndən istifadə etmək bizim üçün mükəmməl idi - sorğu, plan, şablon, ... Biz onu kollektor tərəfində hesablayırıq və hazır ID-ni verilənlər bazasına "tökürük". MD5 uzunluğu və gündəlik bölmə bizə mümkün toqquşmalardan narahat olmamağa imkan verir.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Ancaq bütün bunları tez bir zamanda qeyd etmək üçün biz qeyd prosedurunun özünü dəyişdirməli olduq.

Məlumat adətən necə yazılır? Bizdə bir növ verilənlər bazası var, onu bir neçə cədvələ parçalayırıq, sonra KOPYALAYIB - əvvəlcə birinciyə, sonra ikinciyə, üçüncüyə... Bu, əlverişsizdir, çünki biz üç addımda ardıcıl olaraq bir məlumat axını yazırıq. . Xoşagəlməz. Daha sürətli etmək olarmı? Bacarmaq!

Bunun üçün sadəcə bu axınları bir-birinə paralel olaraq parçalamaq kifayətdir. Belə çıxır ki, ayrı-ayrı mövzularda uçan səhvlərimiz, sorğularımız, şablonlarımız, kilidlərimiz var, ... - və biz hamısını paralel olaraq yazırıq. Bunun üçün kifayətdir hər bir fərdi hədəf cədvəlinə daimi açıq KOPYA kanalını saxlayın.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Yəni kollektor həmişə bir axın var, mənə lazım olan məlumatları yaza biləcəyim. Ancaq verilənlər bazası bu məlumatları görsün və kimsə kilidlərdə qalmasın, bu məlumatların yazılmasını gözləsin, COPY müəyyən fasilələrlə kəsilməlidir. Bizim üçün 100 ms sifariş müddəti ən təsirli oldu - biz onu bağlayırıq və dərhal eyni cədvələ yenidən açırıq. Bəzi zirvələrdə kifayət qədər bir axınımız yoxdursa, müəyyən bir həddə qədər birləşirik.

Əlavə olaraq, belə bir yük profili üçün qeydlər paketlərdə toplandıqda hər hansı bir birləşmənin pis olduğunu öyrəndik. Klassik pislik INSERT ... VALUES və daha 1000 qeyd. Çünki o zaman mediada yazma pik nöqtəniz var və diskə nəsə yazmağa çalışan hər kəs gözləyəcək.

Bu cür anomaliyalardan qurtulmaq üçün sadəcə heç nəyi birləşdirməyin, heç bufer etməyin. Və əgər diskə buferləmə baş verərsə (xoşbəxtlikdən, Node.js-də Stream API sizə bunu öyrənməyə imkan verir) - bu əlaqəni təxirə salın. Məhz o zaman sizə bir hadisə gəlir ki, o, yenidən pulsuzdur - ona yığılmış növbədən yazın. Bu vaxt məşğuldur - hovuzdan növbəti pulsuzunu götür və ona yaz.

Məlumat yazmaq üçün bu yanaşmanı tətbiq etməzdən əvvəl təxminən 4K yazma əməliyyatımız var idi və bu yolla yükü 4 dəfə azaltdıq. İndi onlar yeni monitorinq edilən verilənlər bazası hesabına daha 6 dəfə artıb - 100MB/s-ə qədər. İndi biz son 3 ay ərzində logları təxminən 10-15 TB həcmində saxlayırıq, ümid edirik ki, istənilən tərtibatçı üç ay ərzində istənilən problemi həll edə bilər.

Biz problemləri başa düşürük

Ancaq bütün bu məlumatları toplamaq yaxşıdır, faydalıdır, uyğundur, lakin kifayət deyil - bunu başa düşmək lazımdır. Çünki bunlar gündə milyonlarla müxtəlif planlardır.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Amma milyonlar idarəolunmazdır, əvvəlcə "kiçik" etmək lazımdır. Və, ilk növbədə, bu "kiçik" olanı necə təşkil edəcəyinizə qərar verməlisiniz.

Biz özümüz üçün üç əsas məqamı müəyyən etdik:

  • kim bu sorğunu göndərdi
    Yəni hansı proqramdan “gəlib”: veb interfeysi, backend, ödəniş sistemi və ya başqa bir şey.
  • hara baş verdi
    Hansı xüsusi serverdə. Çünki bir proqram altında bir neçə serveriniz varsa və birdən biri “kötür”sə (çünki “disk çürükdür”, “yaddaş sızıb”, bəzi başqa problemlər), o zaman serverə xüsusi müraciət etməlisiniz.
  • kimi problem bu və ya digər şəkildə özünü göstərirdi

Bizə sorğu göndərən "kimin" olduğunu başa düşmək üçün adi alətdən istifadə edirik - sessiya dəyişənini təyin etmək: SET application_name = '{bl-host}:{bl-method}'; - sorğunun gəldiyi biznes məntiqi hostunun adını və onu başlatan metod və ya tətbiqin adını göndəririk.

Sorğunun "master" ini keçdikdən sonra o, jurnalda göstərilməlidir - bunun üçün dəyişəni konfiqurasiya edirik log_line_prefix = ' %m [%p:%v] [%d] %r %a'. Maraqlananlar üçün ola bilər təlimata baxınbunların hamısı nə deməkdir. Belə çıxır ki, jurnalda görürük:

  • vaxt
  • proses və əməliyyat identifikatorları
  • əsas adı
  • Bu sorğunu göndərən şəxsin İP
  • və metodun adı

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Bundan əlavə, başa düşdük ki, müxtəlif serverlər arasında bir sorğu üçün korrelyasiyaya baxmaq çox maraqlı deyil. Nadir hallarda belə bir vəziyyətlə qarşılaşırsınız ki, sizin bir tətbiqiniz eyni dərəcədə "boş" olur. Ancaq eyni olsa belə - bu serverlərdən hər hansı birinə baxın.

Beləliklə, kəsin bir gün bir server hər hansı bir təhlil üçün kifayət qədər tapdıq.

Birinci analitik bölmə də eynidir "nümunə" - bütün rəqəmsal göstəricilərdən təmizlənmiş plan təqdimatının qısaldılmış forması. İkinci kəsmə tətbiq və ya üsul, üçüncüsü isə bizə problem yaradan xüsusi plan qovşağıdır.

Konkret nümunələrdən şablonlara keçəndə eyni anda iki üstünlük əldə etdik:

  • təhlil üçün obyektlərin sayının dəfələrlə azalması
    Artıq problemi minlərlə sorğu və ya planla deyil, onlarla nümunə ilə təhlil etməliyik.
  • zaman çizelgesi
    Yəni müəyyən bölmə daxilində “faktları” ümumiləşdirməklə onların gün ərzində görünüşünü göstərmək olar. Və burada başa düşə bilərsiniz ki, əgər sizdə, məsələn, saatda bir dəfə baş verən bir nümunə varsa, amma bu - gündə bir dəfə, nəyin səhv getdiyini düşünməlisən - kim tərəfindən və niyə çağırıldı, bəlkə də burada olmalıdır. etməməlidir. Bu başqa bir qeyri-rəqəmsal, sırf vizual analiz üsuludur.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Qalan üsullar plandan çıxardığımız göstəricilərə əsaslanır: belə bir nümunənin neçə dəfə baş verdiyi, ümumi və orta vaxt, diskdən nə qədər məlumat oxunduğu və yaddaşdan nə qədər ...

Çünki, məsələn, hostun analitika səhifəsinə gəlirsən, baxın - diskdə oxumaq üçün çox şey var. Serverdəki disk öhdəsindən gələ bilmir - və ondan kim oxuyur?

Və hər hansı bir sütuna görə çeşidləyə və hazırda nə ilə məşğul olacağınıza qərar verə bilərsiniz - prosessorun və ya diskdəki yüklə və ya sorğuların ümumi sayı ilə ... Çeşidləndi, "yuxarı" olanlara baxdı, düzəltdi. - tətbiqin yeni versiyasını təqdim etdi.
[video mühazirə]

Və dərhal kimi bir sorğudan eyni şablonla gedən müxtəlif tətbiqləri görə bilərsiniz SELECT * FROM users WHERE login = 'Vasya'. Frontend, backend, processing... Və təəccüblənirsən ki, istifadəçi onunla əlaqə saxlamırsa, emal niyə onu oxumalıdır.

Tətbiqdən nə etdiyini dərhal görmək üçün tərs yoldur. Məsələn, frontend bu, bu, bu və bu saatda bir dəfədir (yalnız vaxt qrafiki kömək edir). Və dərhal sual yaranır - görünür, saatda bir dəfə nəsə etmək cəbhəçinin işi deyil ...

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Bir müddətdən sonra anladıq ki, bizdə ümumilik yoxdur plan qovşaqları üzrə statistika. Planlardan yalnız cədvəllərin məlumatları ilə bir şey edən qovşaqları təcrid etdik (onları indekslə oxuyun / yazın və ya yox). Əslində, əvvəlki şəkilə gəldikdə, yalnız bir cəhət əlavə olunur - bu node bizə nə qədər qeydlər gətirdi, və nə qədər atıldı (Sətrlər Filtrlə Silindi).

Plitədə uyğun indeksiniz yoxdur, ona müraciət edirsiniz, indeksin yanından uçur, Seq Scan-a düşür ... birindən başqa bütün qeydləri filtrlədiniz. Və niyə gündə 100 milyon süzülmüş qeydə ehtiyacınız var, indeksi toplamaq daha yaxşı deyilmi?

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Bütün planları qovşaqlar üzrə təhlil etdikdən sonra başa düşdük ki, planlarda çox güman ki, şübhəli görünən bəzi tipik strukturlar var. Tərtibatçıya demək yaxşı olardı: "Dost, burada əvvəlcə indekslə oxuyursan, sonra çeşidləyirsən və sonra kəsirsən" - bir qayda olaraq, bir giriş var.

Sorğu yazan hər kəs yəqin ki, belə bir nümunə ilə qarşılaşıb: "Mənə Vasya üçün son sifarişi, onun tarixini verin." Əgər tarixə görə indeksiniz yoxdursa və ya istifadə etdiyiniz indeksdə tarix yoxdursa, addım atın. məhz belə bir "dırmıq" üzərində .

Ancaq bunun "dırmıq" olduğunu bilirik - niyə dərhal tərtibatçıya nə etməsi lazım olduğunu söyləməyək. Müvafiq olaraq, indi planı açan tərtibatçımız dərhal göstərişləri olan gözəl bir şəkil görür, burada dərhal ona deyilir: "Sizin burada və orada problemləriniz var, amma bunlar bu şəkildə həll olunur."

Nəticədə, əvvəllər problemləri həll etmək üçün lazım olan təcrübənin miqdarı indi əhəmiyyətli dərəcədə azalıb. Burada belə bir alətimiz var.

PostgreSQL sorğularının kütləvi optimallaşdırılması. Kirill Borovikov (tenzor)

Mənbə: www.habr.com

Добавить комментарий