RE:NODE

ბაზები12 წუთის საკითხავი

Postgres-ის vacuum და bloat: MVCC, autovacuum, wraparound

რატომ ტოვებს PostgreSQL მკვდარ ჩანაწერებს, რას აბრუნებს VACUUM, როგორ გაიგო, რომ autovacuum ჩამორჩა, და როგორ გამოასწორო bloat wraparound-მდე.

0 მკითხველი

PostgreSQL არასოდეს ანაცვლებს ჩანაწერს ადგილზე. UPDATE წერს ახალ ვერსიას და ძველს გვერდზე ტოვებს; DELETE ვერსიას მხოლოდ წაშლილად ნიშნავს. ეს მკვდარი ვერსიები რჩება, სანამ VACUUM ადგილს არ დააბრუნებს, და ეს არის მთელი ამბავი table bloat-ის, ცხრილის იდუმალი ზრდის, რომლის ჩანაწერების რაოდენობაც უცვლელია, და transaction wraparound-ის შესახებ შემაშფოთებელი ლოგის შეტყობინების უკან.

კარგი ამბავია, რომ autovacuum ამას შენ მაგივრად აკეთებს და ჯანსაღ ბაზაზე მასზე არასოდეს იფიქრებ. ცუდი ამბავი ისაა, რომ მას შეიძლება სრულიად უკავშირო რამ დაუბლოკოს - დავიწყებული psql სესია ღია ტრანზაქციით, მიტოვებული replication slot - და როცა დაბლოკილია, ცხრილი სამჯერ უფრო დიდი გახდება, ვიდრე უნდა, სანამ რამე გაგაფრთხილებს. ეს პოსტი ისაა, როგორ შეამჩნიო და რა გააკეთო.

რატომ ტოვებს Postgres მკვდარ ჩანაწერებს#

PostgreSQL იყენებს multi-version concurrency control-ს. ყოველ ჩანაწერის ვერსიას აქვს ორი დამალული სვეტი: xmin, ტრანზაქცია, რომელმაც შექმნა, და xmax, ტრანზაქცია, რომელმაც წაშალა ან ჩაანაცვლა. ტრანზაქცია ვერსიას ხედავს, თუ xmin მისი snapshot-ის დაწყებამდე დაკომიტდა, და xmax ან ცარიელია, ან ისეთი ტრანზაქციისაა, რომელსაც ვერ ხედავს.

sql
SELECT xmin, xmax, id, status FROM app.orders WHERE id = 42;

ეს დიზაინი ღირებულ რამეს იძლევა: მკითხველები მწერლებს არასოდეს ბლოკავენ და მწერლები მკითხველებს. გრძელ ანგარიშს შეუძლია ათი წუთი იმუშაოს თანმიმდევრულ snapshot-ზე, სანამ აპლიკაცია წერას აგრძელებს, რადგან ძველი ვერსიები, რომლებიც მას სჭირდება, ჯერ კიდევ არსებობს.

ფასია, რომ ისინი ჯერ კიდევ არსებობს. ცხრილი, სადაც ყოველი ჩანაწერი დღეში ათჯერ განახლდება, საღამოსთვის ყოველი ჩანაწერის თერთმეტ ვერსიას შეიცავს, თუ რამე დანარჩენ ათს არ მოაშორებს. ეს რაღაც სწორედ vacuum-ია.

წინა ვერსია დარჩაარცერთ snapshot-ს არ სჭირდებაადგილი ჩაიწერახელახლა გამოიყენება ადგილზედა ისევ წრეზეUPDATEწერს ახალ ვერსიასძველი ვერსიაჯერ გვერდზეაAutovacuumამოწმებს ყოველ 60 წამშიFree space mapხელახლა გამოსაყენებელი ადგილახალი ჩანაწერებიავსებს ხვრელებს
განახლებული ჩანაწერის ცხოვრება

რას აკეთებს VACUUM და რას არა#

მარტივი VACUUM სკანირებს ცხრილს, პოულობს ჩანაწერის ვერსიებს, რომლებსაც ვერცერთი მომუშავე ტრანზაქცია ვეღარ ხედავს, და ამ ადგილს ხელახლა გამოსაყენებლად ნიშნავს. კერძოდ, ის:

  • შლის მკვდარ ჩანაწერის ვერსიებს და მათ ინდექსის ჩანაწერებს.
  • ათავისუფლებულ ადგილს წერს free space map-ში, რომ ახალი ჩანაწერები მასში ჩაიწეროს.
  • განაახლებს visibility map-ს, რაც index-only scan-ებს აძლევს საშუალებას.
  • აყინავს ძველ ჩანაწერის ვერსიებს, რომ მათი ტრანზაქციის id-ები ხელახლა გამოიყენებოდეს.
  • აჭრის ცხრილის ბოლოში ცარიელ გვერდებს, რისთვისაც მოკლედ იღებს exclusive lock-ს.

რასაც ის არ აკეთებს, არის ადგილის დაბრუნება ოპერაციულ სისტემაზე. ცხრილი, რომელიც 4 GB-მდე გაიზარდა და 1 GB ცოცხალ მონაცემამდე გაიწმინდა, დისკზე მაინც 4 GB-ს იკავებს; განსხვავება ფაილის შიგნით თავისუფალი ადგილია, რომელსაც PostgreSQL ხელახლა გამოიყენებს. ცხრილისთვის, რომელიც სტაბილური ტემპით ცვლის მონაცემებს, ეს ზუსტად სწორია - ადგილი სამუდამოდ ხელახლა გამოიყენება და არაფრის გადაწერა არ არის საჭირო. ეს პრობლემაა მხოლოდ ერთჯერადი მოვლენის შემდეგ, მაგალითად ცხრილის 80%-ის წაშლისას, როცა ადგილი აღარასოდეს დაგჭირდება.

ANALYZE ცალკე სამუშაოა, რომელიც ცხრილის ნიმუშს იღებს და განაახლებს სტატისტიკას, რომელსაც planner იყენებს. Autovacuum ორივეს უშვებს, ცალკეული ზღვრებით. VACUUM (VERBOSE, ANALYZE) app.orders; მათ ხელით ერთად აკეთებს და ბეჭდავს, რაც იპოვა, და ეს პირველი ბრძანებაა, რომელიც უნდა გაუშვა, როცა რამეს ეჭვობ.

VACUUM FULL სახელის მიუხედავად სხვა ოპერაციაა. ის მთელ ცხრილს ახალ ფაილში გადაწერს, რაც ადგილს ოპერაციულ სისტემას ნამდვილად უბრუნებს, და მთელი ხნის განმავლობაში ACCESS EXCLUSIVE lock-ს ინახავს - არც კითხვა, არც ჩაწერა, არაფერი. მას ასევე ცხრილისა და მისი ინდექსების მეორე ასლისთვის საკმარისი თავისუფალი დისკი სჭირდება. ეს მოვლის ფანჯრის ხელსაწყოა და არა რუტინული.

Autovacuum-ის ზღვრები რეალური რიცხვებით#

Autovacuum ყოველ autovacuum_naptime-ში (ნაგულისხმევად ერთი წუთი) იღვიძებს, ყოველ ცხრილს ათვალიერებს და თუ ცხრილი თავის ზღვარს გადასცდა, worker-ს იწყებს. სამი ზღვარია და ისინი არითმეტიკაა და არა მაგია:

სამუშაოფორმულა ნაგულისხმევი მნიშვნელობებით1,000,000 ჩანაწერიან ცხრილზე
Vacuum50 + 0.2 × rows მკვდარი200,050 მკვდარი ჩანაწერი
Analyze50 + 0.1 × rows შეცვლილი100,050 ცვლილება
Insert vacuum1000 + 0.2 × rows ჩამატებული201,000 ჩამატება

insert-ით გამოწვეული vacuum PostgreSQL 13-ში დაემატა და მნიშვნელოვანია მხოლოდ დამატებადი ცხრილებისთვის, რომლებსაც მკვდარი ჩანაწერები არ აქვთ, მაგრამ მაინც სჭირდებათ გაყინვა და visibility-map-ის მოვლა.

კიდევ სამი პარამეტრი განსაზღვრავს, რამდენად ძლიერად მუშაობს worker დაწყების შემდეგ: autovacuum_max_workers (3), autovacuum_vacuum_cost_limit (იღებს vacuum_cost_limit-ს, 200) და autovacuum_vacuum_cost_delay (2 ms PostgreSQL 12-იდან, ხოლო მანამდე 20 ms). ერთად ისინი vacuum-ს ზღუდავენ, რომ დისკი არ გადატვირთოს. თანამედროვე საცავზე ნაგულისხმევი შეზღუდვა კონსერვატიულია; cost limit-ის ამაღლება ჩვეულებრივი პირველი ცვლილებაა, და PostgreSQL-ის ტიუნინგი პატარა სერვერებისთვის მას დანარჩენ კონფიგურაციასთან კონტექსტში აჩვენებს.

ნაგულისხმევი 20% scale factor არის პარამეტრი, რომელთანაც ღირს კამათი. 10-მილიონიან ცხრილზე ის ნიშნავს ორ მილიონ მკვდარ ჩანაწერს, სანამ რამე მოხდება, და შემდეგ ერთ უზარმაზარ vacuum-ს. პატარა სერვერზე უფრო პატარა და უფრო ხშირი უკეთესია.

რატომ ჩამორჩება autovacuum#

Vacuum მხოლოდ იმ ჩანაწერის ვერსიას შლის, რომელიც არცერთ მომუშავე ტრანზაქციას არ შეიძლება დასჭირდეს. სწორედ ეს ერთი წესი დგას ყოველი შემთხვევის უკან, როცა "autovacuum განუწყვეტლივ მუშაობს და ცხრილი მაინც იზრდება".

გრძელი ტრანზაქცია. სესია, რომელმაც საათის წინ BEGIN გაუშვა, snapshot-ს ინახავს და ყოველი მკვდარი ჩანაწერი, რომელიც მას შემდეგ შეიქმნა, უნდა დარჩეს, თუ ის მას შეხედავს. მათ შორისაა სესია, რომელიც idle in transaction მდგომარეობაშია და ჩვეულებრივ აპლიკაციაა, რომელმაც ტრანზაქცია გახსნა, სხვა რამეს მოსთხოვა და დაივიწყა.

მიტოვებული replication slot. slot უკან იჭერს xmin ჰორიზონტს replica-სთვის, რომელიც შეიძლება არასოდეს დაბრუნდეს. არააქტიური slot მთელ cluster-ზე vacuum-ს სიამოვნებით შეაჩერებს.

მოძველებული prepared ტრანზაქცია. ორფაზიანი commit, რომელიც მომზადდა და არასოდეს დაკომიტდა. იშვიათია და სრულიად უხილავი, სანამ არ მოძებნი.

Standby feedback. hot_standby_feedback = on-ისას replica-ზე გრძელი query primary-ზე გასუფთავებას აყოვნებს. ამისთვისაა ის, მაგრამ ნიშნავს, რომ replica-ზე ანგარიშმა primary-ის bloat შეიძლება გამოიწვიოს.

ოთხივე იპოვე სამი query-ით:

sql
-- Sessions holding back cleanup, oldest firstSELECT pid, state, age(backend_xmin) AS xmin_age,       now() - xact_start AS transaction_age, left(query, 60) AS queryFROM pg_stat_activityWHERE backend_xmin IS NOT NULLORDER BY age(backend_xmin) DESC;-- Replication slots, active or notSELECT slot_name, active, age(xmin) AS xmin_age, wal_statusFROM pg_replication_slots;-- Forgotten prepared transactionsSELECT gid, prepared, owner, database FROM pg_prepared_xacts;

პირველის გამოსავალია idle_in_transaction_session_timeout, role-ზე დაყენებული, რომ დავიწყებული სესია თავისით დაიხუროს ერთ წუთში და არა შაბათ-კვირის შემდეგ. მეორის გამოსავალია slot-ის წაშლა, როცა დარწმუნდები, რომ replica აღარ არსებობს. კიდევ ორი მიზეზი დასახელებას იმსახურებს: ცხრილი, რომელიც იმდენად დიდია, რომ ერთ worker-ს შემდეგი ციკლის დაწყებამდე დასრულება არ ესწრება, და lock-ები - VACUUM DDL-ს ანებებს, ამიტომ autovacuum შეიძლება განმეორებით გაუქმდეს migration-მა, რომელიც განუწყვეტლივ იღებს კონფლიქტურ lock-ს.

მკვდარი ჩანაწერებისა და bloat-ის გაზომვა#

სტატისტიკის view-ები მკვდარი ჩანაწერების რაოდენობას უფასოდ გაძლევს. ეს არის query, რომელიც უნდა შეინახო:

sql
SELECT relname AS table,       n_live_tup AS live, n_dead_tup AS dead,       round(100 * n_dead_tup / GREATEST(n_live_tup + n_dead_tup, 1)) AS dead_pct,       last_autovacuum, last_autoanalyze, autovacuum_countFROM pg_stat_user_tablesWHERE n_dead_tup > 1000ORDER BY n_dead_tup DESCLIMIT 20;

ცხრილი დაახლოებით 20%-ზე მეტი მკვდარით და last_autovacuum-ით null ან დღეების წინანდელი არის სიგნალი. ზუსტი პასუხისთვის და არა შეფასებისთვის, pgstattuple გაფართოება ცხრილს კითხულობს და ზუსტად გეუბნება:

sql
CREATE EXTENSION IF NOT EXISTS pgstattuple;SELECT * FROM pgstattuple('app.orders');          -- exact, reads everythingSELECT * FROM pgstattuple_approx('app.orders');   -- fast estimate

dead_tuple_percent და free_percent არის ორი სვეტი, რომელიც მნიშვნელოვანია. ცხრილი 5% თავისუფალი ადგილით ჯანსაღია; ცხრილი 60% თავისუფალი ადგილით რაღაცაში გავიდა.

სანამ vacuum მუშაობს, pg_stat_progress_vacuum აჩვენებს, რომელ ფაზაშია და ცხრილის რამდენი გაიარა, რაც პასუხობს კითხვას "გაიჭედა თუ უბრალოდ ნელია". და თუ შენი სერვერი standard output-ში წერს, log_autovacuum_min_duration = 1s-ის დაყენება ხაზს ლოგში დებს ყოველ ჯერზე, როცა vacuum ერთ წამზე მეტ ხანს გრძელდება - ეს ყველაზე იაფი ადრეული გაფრთხილებაა და ის იქ ვარდება, სადაც კონსოლს უკვე კითხულობ. ზოგადი პრინციპი აღწერილია პოსტში მონიტორინგი, რომელიც რამეს გეუბნება: რიცხვი, რომელსაც არავინ უყურებს, მონიტორინგი არ არის.

Vacuum-ის ტიუნინგი თითო ცხრილზე#

გლობალური პარამეტრები ბლაგვი ინსტრუმენტია, რადგან ცხრილი, რომელსაც ყურადღება სჭირდება, თითქმის არასოდეს არის საშუალო. თითო ცხრილის storage პარამეტრები მათ გადაფარავს:

sql
-- A hot table: clean at 1% dead, and do not throttleALTER TABLE app.sessions SET (  autovacuum_vacuum_scale_factor = 0.01,  autovacuum_vacuum_threshold = 100,  autovacuum_vacuum_cost_delay = 0);-- A big append-only table: analyze more often, vacuum on insertsALTER TABLE app.events SET (  autovacuum_analyze_scale_factor = 0.02,  autovacuum_vacuum_insert_scale_factor = 0.05);

მეორე პარამეტრი, რომლის ცოდნაც ღირს, არის fillfactor. ნაგულისხმევად ის 100-ია, რაც ნიშნავს, რომ გვერდები მთლიანად ივსება. დააყენე 90 ცხრილზე, რომლის ჩანაწერებიც ხშირად განახლდება, და PostgreSQL ყოველ გვერდზე ადგილს ტოვებს, რომ ჩანაწერის ახალი ვერსია ძველის გვერდით იცხოვროს. ეს ჩართავს heap-only tuple განახლებას, რომელსაც ინდექსებს შეხება საერთოდ არ სჭირდება - ბევრად იაფია და vacuum-ს ნაკლებს უტოვებს გასასუფთავებლად. ის მხოლოდ ცვლილების შემდეგ ჩაწერილ გვერდებზე მუშაობს, ამიტომ თანდათან ვრცელდება.

sql
ALTER TABLE app.sessions SET (fillfactor = 90);

გაითვალისწინე ურთიერთქმედება ინდექსებთან: HOT განახლება შესაძლებელია მხოლოდ მაშინ, როცა არცერთი ინდექსირებული სვეტი არ შეცვლილა. ინდექსი სვეტზე, რომელსაც შენი აპლიკაცია განუწყვეტლივ ანახლებს, ორჯერ გიჯდება, და ეს ერთ-ერთი მიზეზია, რის გამოც PostgreSQL-ის ინდექსები ახსნილი მეტი ინდექსის ნაცვლად ნაკლებს უჭერს მხარს.

ტრანზაქციის ID wraparound#

ტრანზაქციის id-ები 32-ბიტიანი რიცხვებია. PostgreSQL წარსულში დაახლოებით ორ მილიარდ ტრანზაქციას ხედავს; ამის მიღმა id მომავალში გამოჩნდებოდა და ძველი ჩანაწერები უხილავი გახდებოდა - ჩუმი, კატასტროფული მონაცემების დაკარგვა. ამის თავიდან ასაცილებლად vacuum აყინავს ძველ ჩანაწერის ვერსიებს და მათ ყველასთვის ხილულად ნიშნავს ტრანზაქციის id-ის მიუხედავად.

სწორედ ამიტომ არ არის vacuum არჩევითი და ამიტომ უშვებს PostgreSQL anti-wraparound vacuum-ს ცხრილზე, რომლის უძველესი გაუყინავი ტრანზაქცია autovacuum_freeze_max_age-ს (200 მილიონი) აღწევს, თუნდაც autovacuum სრულად გამორთული იყოს. შეამოწმე, სად დგახარ:

sql
SELECT datname, age(datfrozenxid) AS xid_ageFROM pg_database ORDER BY xid_age DESC;SELECT relname, age(relfrozenxid) AS xid_ageFROM pg_class WHERE relkind IN ('r','m','t')ORDER BY xid_age DESC LIMIT 10;

200 მილიონზე ნაკლები ნორმალურია. მასზე მუდმივად ზრდა ნიშნავს, რომ anti-wraparound vacuum ზემოთ სექციის მიზეზებიდან ერთ-ერთით ბლოკირებულია - იპოვე ის ახლავე, რადგან საათი არ ჩერდება. ზღვართან მიახლოებისას სერვერი სულ უფრო მკაცრ warning-ებს წერს და საშიშ წერტილამდე უარს ამბობს ტრანზაქციების დაწყებაზე, რომლებსაც ახალი id სჭირდება. VACUUM თავად ამ წერტილშიც მუშაობს, რითაც აღდგები; ლოგის მინიშნება single-user რეჟიმზე ბოლო გამოსავალია და არა პირველი ნაბიჯი.

თანამედროვე ვერსიებზე ორი შემამსუბუქებელი საშუალება არსებობს. PostgreSQL 14-მა დაამატა failsafe, რომელიც vacuum-ს აიძულებს, გამოტოვოს ინდექსების გასუფთავება და უგულებელყოს cost delay-ები, როცა ცხრილი საშიშად ძველი ხდება, რომ დისკის სიჩქარით დასრულდეს. ხოლო PostgreSQL 17-მა გადააკეთა, როგორ აკვირდება vacuum მკვდარი ჩანაწერის მიმთითებლებს მეხსიერებაში და მოხსნა ძველი ეფექტური 1 GB ლიმიტი მეხსიერებაზე, რომელსაც ერთი vacuum იყენებდა, რაც უარეს შემთხვევებს მნიშვნელოვნად ამოკლებს. არცერთი არ ცვლის იმის გარკვევას, რამ დაბლოკა გასუფთავება თავიდანვე.

Multixact id-ებს ამ პრობლემის საკუთარი, პარალელური ვერსია აქვთ, რომელსაც განსაზღვრავს autovacuum_multixact_freeze_max_age (400 მილიონი). მათ ხარჯავს row-level lock-ები, როგორიცაა SELECT ... FOR SHARE, ამიტომ მძიმე დაბლოკვის დატვირთვას ეს ლიმიტი პირველი შეიძლება მიაღწიოს.

Bloat-ის გამოსწორება, რომელიც უკვე მოხდა#

როცა ცხრილი უკვე გაბერილია, მარტივი vacuum ფაილს არ შეამცირებს. ვარიანტები, ყველაზე ცუდიდან საუკეთესომდე:

  1. დატოვე. თუ ცხრილი ადგილს თავისი ნორმალური ტემპით ხელახლა გამოიყენებს, არაფერი გააკეთო. ეს სწორი პასუხია უფრო ხშირად, ვიდრე ხალხს სჯერა.
  2. `VACUUM FULL app.orders;` ცხრილს გადაწერს, ადგილს დააბრუნებს, exclusive lock-ს იღებს და მეორე ასლისთვის დისკი სჭირდება. კარგია 200 MB ცხრილისთვის ღამის 3 საათზე და არა 40 GB-იანისთვის დღისით.
  3. `pg_repack`. გაფართოება, რომელიც იგივე გადაწერას ცხრილის ხელმისაწვდომად შენარჩუნებით აკეთებს და მოკლე lock-ს მხოლოდ ჩანაცვლებისას იღებს. მას მაინც სჭირდება ასლისთვის დისკის ადგილი და სერვერზე უნდა იყოს დაყენებული, რასაც ყველა ჰოსტი არ უშვებს.
  4. Dump და restore. მთელი ბაზისთვის, რომელიც ძალიან ცუდად წავიდა, pg_dump და ახალში აღდგენა ყველაზე კომპაქტურ შედეგს იძლევა. ეს ასევე მომსახურების შეწყვეტაა. pg_dump-ისა და pg_restore-ის გზამკვლევი ფარავს ფორმატებსა და პარალელურ ვარიანტებს.
  5. დაყავი partition-ებად და მერე წაშალე. თუ bloat ძველი ჩანაწერების წაშლიდან მოდის, ამის ნაცვლად დროის მიხედვით დაყავი partition-ებად. partition-ის წაშლა მყისიერია და არაფერს ტოვებს vacuum-ისთვის.

ინდექსებიც bloat-დება, და ცალკე. REINDEX INDEX CONCURRENTLY orders_created_idx; (PostgreSQL 12 და უფრო ახალი) ერთს ჩაწერის დაბლოკვის გარეშე თავიდან აგებს და ჩვეულებრივ უკეთესი პირველი ნაბიჯია, ვიდრე ცხრილის სრული გადაწერა, რადგან ინდექსის bloat უფრო გავრცელებულია და თავიდან აგება უფრო იაფია.

ორი პრაქტიკული შენიშვნა დისკზე. VACUUM FULL და pg_repack ორივეს ერთდროულად სჭირდება ცხრილის დაახლოებით ორმაგი ზომა თავისუფალი, რაც 20 GB გეგმაზე რეალური შეზღუდვაა - დაწყებამდე შეამოწმე pg_total_relation_size. და აიღე backup ჯერ. RE:NODE-ზე backup slot-ები ყველა ბაზის გეგმას მოჰყვება, backup-ები ინახება იმ მანქანის გარეთ, რომელსაც იცავენ, და აღდგენა ღილაკია და არა მხარდაჭერის ბილეთი; პანელი ასევე დისკს გეგმის ლიმიტთან ერთად გრაფიკზე აჩვენებს, ამიტომ ხედავ, დაეტევა თუ არა გადაწერა. არგუმენტი, ერთხელ განზრახ დააჭირო restore-ს, აღწერილია პოსტში ბაზის backup და იმის დამტკიცება, რომ ის აღდგება.

ერთი ბოლო მოკლე გზა, რომლის ცოდნაც ღირს: ცხრილის სრულად დასაცარიელებლად TRUNCATE მყისიერია და ადგილს მაშინვე აბრუნებს, რადგან ჩანაწერებს მკვდრად ნიშნავს კი არა, ახალ ცარიელ ფაილს ქმნის. DELETE FROM table მილიონ ჩანაწერზე ქმნის მილიონ მკვდარ ჩანაწერს და შემდეგ ძალიან გრძელ vacuum-ს.

FAQ#

რა არის table bloat PostgreSQL-ში?

ცხრილის ფაილებში ადგილი, რომელსაც იკავებს ჩანაწერის ვერსიები, რომლებსაც ვეღარაფერი ხედავს. ის მოდის განახლებებიდან და წაშლებიდან, რომლებიც ადგილზე არასოდეს გადაწერენ. Vacuum ამ ადგილს ხელახლა გამოსაყენებლად აქცევს; ის ფაილს არ ამცირებს, სანამ ცხრილს არ გადაწერ.

უნდა გავუშვა VACUUM ხელით?

ჩვეულებრივ არა - autovacuum რუტინულ სამუშაოს cron job-ზე უკეთ ასრულებს, რადგან რეალურ ცვლილებაზე რეაგირებს. გაუშვი VACUUM (ANALYZE) ხელით მასობრივი ჩატვირთვის ან მასობრივი წაშლის შემდეგ, როცა გინდა, რომ სტატისტიკა მაშინვე განახლდეს და არა შემდეგ ზღვარზე.

უსაფრთხოა VACUUM FULL-ის გაშვება production-ზე?

ის უსაფრთხოა შენი მონაცემებისთვის და მტრულია შენი ხელმისაწვდომობისადმი: მთელი გადაწერის განმავლობაში exclusive lock-ს იღებს და ცხრილის მეორე ასლისთვის დისკი სჭირდება. დაგეგმე ის, ან გამოიყენე pg_repack, თუ შენი ჰოსტი გაფართოებას უშვებს.

რატომ მუშაობს autovacuum განუწყვეტლივ, მაგრამ ცხრილი მაინც იზრდება?

რაღაც xmin ჰორიზონტს უკან იჭერს, ამიტომ vacuum ვერაფერს პოულობს, რისი წაშლაც უფლება აქვს. მოძებნე ძველი ტრანზაქცია pg_stat_activity-ში, არააქტიური replication slot ან prepared ტრანზაქცია, რომელიც არასოდეს დაკომიტებულა.

რა ხდება, თუ transaction wraparound ნამდვილად დადგება?

სერვერი ახალი ტრანზაქციის id-ების გაცემას წყვეტს მონაცემების დასაცავად და არა დასაკარგად. Vacuum კვლავ მუშაობს, ამიტომ აღდგენა ისაა, რომ anti-wraparound vacuum დაასრულოს მას შემდეგ, რაც ის, რაც ბლოკავდა, მოაშორე. მისი სრულად თავიდან აცილება შესაძლებელია age(datfrozenxid)-ზე თვალის დევნებით.

ანელებს თუ არა მკვდარი ჩანაწერების დიდი რაოდენობა query-ებს?

დიახ, ორი გზით. ცხრილი მეტ გვერდს იკავებს, ამიტომ scan-ები მეტს კითხულობს და cache-ში პროპორციულად ნაკლები რეალური მონაცემი ეტევა. და ცხრილი, რომელსაც vacuum ვერ ეწევა, კარგავს index-only scan-ებს, რადგან visibility map არასოდეს არის განახლებული.


კომენტარები

სრულიად ანონიმურად: ანგარიშის, ელფოსტის და cookie-ის გარეშე. ინახება მხოლოდ სახელი, ტექსტი და დრო - სხვა არაფერი. ბმულების რაოდენობა ლიმიტირებულია.

0/2000