پوسټګریس: بلوټ، pg_repack او ځنډول شوي خنډونه

پوسټګریس: بلوټ، pg_repack او ځنډول شوي خنډونه

په جدولونو او شاخصونو کې د بلیټ اغیز په پراخه کچه پیژندل شوی او نه یوازې په پوسټګریس کې شتون لري. د دې سره د بکس څخه بهر د معاملې کولو لارې شتون لري ، لکه VACUUM FULL یا CLUSTER ، مګر دوی د عملیاتو پرمهال میزونه بندوي او له همدې امله تل نشي کارول کیدی.

مقاله به د دې په اړه یوه کوچنۍ تیوري ولري چې څنګه بلیټ رامینځته کیږي ، تاسو څنګه ورسره مبارزه کولی شئ ، د ځنډول شوي خنډونو او هغه ستونزو په اړه چې دوی د pg_repack توسیع کارولو ته راوړي.

دا مقاله د دې پر بنسټ لیکل شوې ده زما وینا په PgConf.Russia 2020 کې.

ولې پړسوب رامنځته کیږي؟

پوسټګریس د څو نسخو ماډل پراساس دی (MVCC). د دې جوهر دا دی چې په جدول کې هر قطار کولی شي څو نسخې ولري، پداسې حال کې چې لیږدونه د دې نسخو څخه زیات نه ګوري، مګر اړینه نه ده چې ورته ورته وي. دا ډیری لیږدونو ته اجازه ورکوي چې په یو وخت کې کار وکړي او په حقیقت کې په یو بل باندې هیڅ اغیزه ونلري.

په ښکاره ډول، دا ټولې نسخې باید زیرمه شي. پوسټګریس د حافظې پاڼې سره د پاڼې په واسطه کار کوي او پاڼه د ډیټا لږترلږه اندازه ده چې د ډیسک یا لیکلو څخه لوستل کیدی شي. راځئ چې یو کوچنی مثال وګورو ترڅو پوه شو چې دا څنګه پیښیږي.

راځئ چې ووایو چې موږ یو میز لرو چې موږ څو ریکارډونه اضافه کړي دي. نوي معلومات د فایل په لومړي مخ کې ښکاره شوي چیرې چې میز زیرمه شوی. دا د قطارونو ژوندۍ نسخې دي چې د ژمنې وروسته نورو معاملو ته شتون لري (د سادګۍ لپاره، موږ به فرض کړو چې د انزوا کچه د لوستلو ژمنه ده).

پوسټګریس: بلوټ، pg_repack او ځنډول شوي خنډونه

موږ بیا د ننوتلو څخه یوه تازه کړه، په دې توګه د پخوانۍ نسخه نښه کول نور اړونده ندي.

پوسټګریس: بلوټ، pg_repack او ځنډول شوي خنډونه

ګام په ګام، د قطار نسخو تازه کول او ړنګول، موږ د یوې پاڼې سره پای ته ورسیږو په کوم کې چې نږدې نیمایي ډاټا "کثافات" دي. دا ډاټا د هیڅ لیږد لپاره نه لیدل کیږي.

پوسټګریس: بلوټ، pg_repack او ځنډول شوي خنډونه

Postgres یو میکانیزم لري VACUMUM، کوم چې متروک نسخې پاکوي او د نوي معلوماتو لپاره ځای جوړوي. مګر که دا په کافي اندازه په منظم ډول تنظیم شوی نه وي یا په نورو جدولونو کې په کار بوخت وي ، نو "د کثافاتو ډیټا" پاتې کیږي ، او موږ باید د نوي معلوماتو لپاره اضافي پا pagesې وکاروو.

نو زموږ په مثال کې، په ځینو وختونو کې جدول به څلور پاڼې ولري، مګر یوازې نیمایي به یې ژوندي معلومات ولري. د پایلې په توګه، کله چې میز ته لاسرسی ومومي، موږ به د اړتیا په پرتله ډیر معلومات ولولو.

پوسټګریس: بلوټ، pg_repack او ځنډول شوي خنډونه

حتی که VACUUM اوس ټول غیر اړونده قطار نسخې حذف کړي، وضعیت به په ډراماتیک ډول ښه نشي. موږ به د نویو قطارونو لپاره په پاڼو یا حتی په ټولو پاڼو کې وړیا ځای ولرو، مګر موږ به بیا هم د اړتیا څخه ډیر معلومات ولرو.
د لارې په توګه، که په بشپړه توګه خالي پاڼه (زموږ په مثال کې دویمه برخه) د فایل په پای کې وي، نو بیا VACUUM به وکوالی شي دا پرې کړي. مګر اوس هغه په ​​​​مینځ کې ده، نو د هغې سره هیڅ شی نشي کولی.

پوسټګریس: بلوټ، pg_repack او ځنډول شوي خنډونه

کله چې د داسې خالي یا خورا لږ پاڼو شمیر لوی شي، کوم چې د بلوټ په نوم یادیږي، دا په فعالیت اغیزه کوي.

هرڅه چې پورته تشریح شوي په جدولونو کې د ګل کولو پیښې میکانیکونه دي. په شاخصونو کې دا په ورته ډول پیښیږي.

ایا زه پړسوب لرم؟

د دې معلومولو لپاره څو لارې شتون لري چې تاسو پړسوب لرئ. د لومړي نظر دا دی چې د داخلي پوسټګریس احصایې وکاروئ، کوم چې په میزونو کې د قطارونو شمیر، د "ژوندی" قطارونو شمیر، او داسې نور په اړه نږدې معلومات لري. تاسو کولی شئ په انټرنیټ کې د چمتو شوي سکریپټونو ډیری توپیرونه ومومئ. موږ د اساس په توګه واخیست سکریپټ د PostgreSQL متخصصینو څخه، کوم چې کولی شي د ټوسټ او بلوټ بیټری شاخصونو سره د بلوټ میزونه ارزونه وکړي. زموږ په تجربه کې، دا تېروتنه 10-20٪ ده.

بله لاره د توسیع کارول دي pgstattuple، کوم چې تاسو ته اجازه درکوي د پاڼو دننه وګورئ او دواړه اټکل شوي او دقیق بلیټ ارزښت ترلاسه کړئ. مګر په دوهم حالت کې، تاسو باید ټول میز سکین کړئ.

موږ یو کوچنی بلیټ ارزښت په پام کې نیسو، تر 20٪ پورې، د منلو وړ. دا د فل فکتور د انلاګ په توګه ګڼل کیدی شي میزونه и شاخصونه. په 50٪ او پورته کې، د فعالیت ستونزې ممکن پیل شي.

د زکام سره د مبارزې لارې

پوسټګریس د بکس څخه بهر د بلیټ سره معامله کولو لپاره ډیری لارې لري ، مګر دا تل د هرچا لپاره مناسب ندي.

آټوواکوم تنظیم کړئ ترڅو پړسوب واقع نشي. یا په دقیق ډول، دا په هغه کچه کې وساتئ چې تاسو ته د منلو وړ وي. دا د "کپتان" مشورې په څیر بریښي ، مګر په حقیقت کې دا تل ترلاسه کول اسانه ندي. د مثال په توګه، تاسو د ډیټا سکیما کې د منظم بدلونونو سره فعال پرمختګ لرئ، یا د ډیټا یو څه مهاجرت ترسره کیږي. د پایلې په توګه، ستاسو د بار پروفایل ممکن په مکرر ډول بدل شي او معمولا به له میز څخه میز ته توپیر ولري. دا پدې مانا ده چې تاسو اړتیا لرئ په دوامداره توګه یو څه مخکې کار وکړئ او د هر میز بدلیدونکي پروفایل ته آټوواکوم تنظیم کړئ. مګر په ښکاره ډول دا کار کول اسانه ندي.

بل عام دلیل چې ولې AUTOVACUUM نشي کولی د میزونو سره وساتي ځکه چې دلته اوږدمهاله لیږدونه شتون لري چې دا د دې لیږد لپاره موجود ډیټا پاکولو مخه نیسي. دلته وړاندیز هم څرګند دی - د "ډنګینګ" معاملو څخه ځان خلاص کړئ او د فعال معاملو وخت کم کړئ. مګر که ستاسو په غوښتنلیک کې بار د OLAP او OLTP یو هایبرډ وي، نو تاسو کولی شئ په ورته وخت کې ډیری پرله پسې تازه معلومات او لنډې پوښتنې ولرئ، او همدارنګه د اوږدې مودې عملیات - د بیلګې په توګه، د راپور جوړول. په داسې حالت کې، دا د مختلفو اډو په اوږدو کې د بار د خپریدو په اړه فکر کولو ارزښت لري، کوم چې به د دوی هر یو ډیر ښه کولو ته اجازه ورکړي.

بله بیلګه - حتی که چیرې پروفایل همغږي وي، مګر ډیټابیس د خورا لوړ بار لاندې وي، نو حتی خورا تیریدونکي آټوواکوم ممکن مقابله ونه کړي، او بلیټ به واقع شي. اندازه کول (عمودی یا افقی) یوازینی حل دی.

په داسې حالت کې څه وکړئ چیرې چې تاسو AUTOVACUUM ترتیب کړی وي، مګر تودوخه وده کوي.

ټیم ویکیوم ډک د جدولونو او شاخصونو مینځپانګې بیا رغوي او یوازې اړوند معلومات په دوی کې پریږدي. د بلوټ له مینځه وړو لپاره ، دا په بشپړ ډول کار کوي ، مګر د دې اجرا کولو پرمهال په میز کې یو ځانګړی قفل نیول شوی (AccessExclusiveLock) ، کوم چې به پدې میز کې د پوښتنو پلي کولو ته اجازه ورنکړي ، حتی غوره کوي. که تاسو د دې توان لرئ چې خپل خدمت یا د هغې یوه برخه د یو څه وخت لپاره ودروئ (د لسګونو دقیقو څخه تر څو ساعتونو پورې د ډیټابیس اندازې او ستاسو هارډویر پورې اړه لري) ، نو دا اختیار غوره دی. له بده مرغه، موږ د ټاکل شوي ساتنې په جریان کې د VACUUM FULL چلولو وخت نلرو، نو دا طریقه زموږ لپاره مناسبه نه ده.

ټیم کلچر د میزونو مینځپانګې په ورته ډول د VACUUM FULL په څیر بیا رغوي ، مګر تاسو ته اجازه درکوي یو شاخص مشخص کړئ چې له مخې به یې ډاټا په فزیکي ډول په ډیسک کې ترتیب شي (مګر په راتلونکي کې د نوي قطارونو لپاره ترتیب تضمین ندی). په ځینو حاالتو کې، دا د یو شمیر پوښتنو لپاره ښه اصلاح دی - د شاخص لخوا د ډیری ریکارډونو لوستلو سره. د کمانډ نیمګړتیا د VACUUM FULL په څیر دی - دا د عملیاتو پرمهال میز بندوي.

ټیم REINDEX د تیرو دوو سره ورته، مګر یو ځانګړی شاخص یا د میز ټول شاخصونه بیا رغوي. لاکونه یو څه کمزوري دي: په میز کې ShareLock (د تعدیلاتو مخه نیسي، مګر د انتخاب اجازه ورکوي) او د بیارغونې په شاخص کې AccessExclusiveLock (د دې شاخص په کارولو سره پوښتنې بندوي). په هرصورت، د Postgres په 12 نسخه کې یو پیرامیټر ښکاره شو په ورته وخت کې, کوم چې تاسو ته اجازه درکوي د ریکارډونو اضافه کولو، تعدیل، یا د ریکارډونو له مینځه وړلو پرته شاخص بیا جوړ کړئ.

د پوسټګریس په پخوانیو نسخو کې، تاسو کولی شئ د REINDEX په څیر ورته پایلې ترلاسه کړئ په ورته وخت کې شاخص جوړ کړئ. دا تاسو ته اجازه درکوي پرته له سخت لاک کولو څخه یو شاخص رامینځته کړئ (ShareUpdateExclusiveLock، کوم چې د موازي پوښتنو سره مداخله نه کوي)، بیا زاړه شاخص د نوي سره بدل کړئ او زاړه شاخص حذف کړئ. دا تاسو ته اجازه درکوي پرته له دې چې ستاسو غوښتنلیک سره مداخله وکړئ د انډیکس بلاټ له مینځه ویسي. دا مهمه ده چې په پام کې ونیول شي چې د شاخصونو بیا رغونه به د ډیسک فرعي سیسټم کې اضافي بار وي.

په دې توګه، که چیرې د شاخصونو لپاره "په مچ" کې د بلیټ له منځه وړلو لارې شتون ولري، نو د میزونو لپاره هیڅ شتون نلري. دا هغه ځای دی چې مختلف بهرني توسیعونه په لوبې کې راځي: pg_repack (پخوانی pg_reorg) pgcompact, pgcompactable او نور. په دې مقاله کې، زه به دوی پرتله نه کړم او یوازې به د pg_repack په اړه وغږیږم، کوم چې د یو څه تعدیل وروسته، موږ خپل ځان کاروو.

څنګه pg_repack کار کوي

پوسټګریس: بلوټ، pg_repack او ځنډول شوي خنډونه
راځئ چې ووایو چې موږ یو بشپړ عادي میز لرو - د شاخصونو، محدودیتونو او له بده مرغه، د غوړ سره. د pg_repack لومړی ګام د ټولو بدلونونو په اړه د معلوماتو ذخیره کولو لپاره د لاګ جدول رامینځته کول دي کله چې دا چلیږي. محرک به دا بدلونونه د هر داخلولو، تازه کولو او حذف کولو لپاره نقل کړي. بیا یو جدول رامینځته کیږي ، په جوړښت کې د اصلي سره ورته ، مګر پرته له شاخصونو او محدودیتونو ، ترڅو د معلوماتو داخلولو پروسه ورو نه کړي.

بیا، pg_repack ډیټا د زاړه میز څخه نوي میز ته لیږدوي، په اتوماتيک ډول ټول غیر اړونده قطارونه فلټر کوي، او بیا د نوي میز لپاره شاخصونه جوړوي. د دې ټولو عملیاتو د اجرا کولو په جریان کې، بدلونونه په لاګ جدول کې راټولیږي.

بل ګام دا دی چې بدلونونه نوي میز ته انتقال کړئ. مهاجرت په څو تکرارونو کې ترسره کیږي، او کله چې د لاګ جدول کې له 20 څخه لږ ننوتنې پاتې وي، pg_repack یو پیاوړی قفل ترلاسه کوي، وروستي ډیټا لیږدوي، او د پوسټګریس سیسټم جدولونو کې زوړ میز له نوي سره بدلوي. دا یوازینی او خورا لنډ وخت دی کله چې تاسو به د میز سره کار نشئ کولی. له دې وروسته، زوړ میز او د لاګونو سره میز حذف کیږي او د فایل سیسټم کې ځای خالي کیږي. پروسه بشپړه شوه.

په تیوري کې هرڅه ښه ښکاري، مګر په عمل کې څه پیښیږي؟ موږ pg_repack پرته له بار او د بار لاندې ازموینه وکړه ، او د وخت دمخه بندیدو په صورت کې یې عملیات چیک کړل (په بل عبارت ، د Ctrl+C په کارولو سره). ټولې ازموینې مثبتې وې.

موږ د خواړو پلورنځي ته لاړو - او بیا هرڅه لکه څنګه چې موږ تمه درلوده لاړ نه شو.

لومړی پینکیک په پلور کې

په لومړي کلستر کې موږ د ځانګړي محدودیت څخه د سرغړونې په اړه یوه تېروتنه ترلاسه کړه:

$ ./pg_repack -t tablename -o id
INFO: repacking table "tablename"
ERROR: query failed: 
    ERROR: duplicate key value violates unique constraint "index_16508"
DETAIL:  Key (id, index)=(100500, 42) already exists.

دا محدودیت په اتومات ډول تولید شوی نوم index_16508 درلود - دا د pg_repack لخوا رامینځته شوی. د هغه ځانګړتیاو پراساس چې په جوړښت کې شامل دي، موږ "زموږ" محدودیت ټاکلی چې ورته ورته وي. ستونزه دا شوه چې دا په بشپړه توګه عادي محدودیت نه دی، مګر یو ځنډول شوی (ځنډول شوی محدودیت, i.e. د دې تایید د sql کمانډ څخه وروسته ترسره کیږي، کوم چې د غیر متوقع پایلو المل کیږي.

ځنډول شوي خنډونه: ولې دوی ورته اړتیا لري او دوی څنګه کار کوي

د ځنډول شوي محدودیتونو په اړه یو کوچنی نظر.
راځئ چې یو ساده مثال په پام کې ونیسو: موږ د دوو ځانګړتیاو سره د موټرو میز حواله کتاب لرو - په لارښود کې د موټر نوم او ترتیب.
پوسټګریس: بلوټ، pg_repack او ځنډول شوي خنډونه

create table cars
(
  name text constraint pk_cars primary key,
  ord integer not null constraint uk_cars unique
);



راځئ چې ووایو موږ اړتیا لرو چې لومړی او دوهم موټر بدل کړو. مستقیم حل دا دی چې لومړی ارزښت دویم ته تازه کړئ، او دویم لومړی ته:

begin;
  update cars set ord = 2 where name = 'audi';
  update cars set ord = 1 where name = 'bmw';
commit;

مګر کله چې موږ دا کوډ چلوو، موږ د خنډ سرغړونې تمه کوو ځکه چې په جدول کې د ارزښتونو ترتیب ځانګړی دی:

[23305] ERROR: duplicate key value violates unique constraint “uk_cars”
Detail: Key (ord)=(2) already exists.

زه څنګه کولی شم دا په مختلف ډول ترسره کړم؟ یو انتخاب: یو امر ته د اضافي ارزښت ځای په ځای کول اضافه کړئ چې تضمین شوی وي چې په جدول کې شتون نلري، د بیلګې په توګه "-1". په برنامه کولو کې ، دې ته "د دریمې برخې له لارې د دوه متغیرونو ارزښتونو تبادله" ویل کیږي. د دې میتود یوازینۍ نیمګړتیا اضافي تازه کول دي.

دوهم اختیار: جدول بیا ډیزاین کړئ ترڅو د انټیجرونو پرځای د ترتیب ارزښت لپاره د فلټینګ پوائنټ ډیټا ډول وکاروئ. بیا، کله چې ارزښت له 1 څخه تازه کړئ، د بیلګې په توګه، 2.5 ته، لومړی ننوتل به په اتوماتيک ډول د دویم او دریم تر منځ "ودریږي". دا حل کار کوي، مګر دوه محدودیتونه شتون لري. لومړی، دا به ستاسو لپاره کار ونکړي که چیرې ارزښت په انٹرفیس کې چیرته کارول کیږي. دوهم، د ډیټا ډول دقت پورې اړه لري، تاسو به د ټولو ریکارډونو ارزښتونو بیا محاسبه کولو دمخه محدود شمیر احتمالي داخلونه ولرئ.

دریم اختیار: محدودیت ځنډول شوی ترڅو دا یوازې د ژمنې په وخت کې چیک شي:

create table cars
(
  name text constraint pk_cars primary key,
  ord integer not null constraint uk_cars unique deferrable initially deferred
);

څرنګه چې زموږ د لومړنۍ غوښتنې منطق دا یقیني کوي چې ټول ارزښتونه د ژمنې په وخت کې ځانګړي دي، دا به بریالي شي.

پورته بحث شوی مثال، البته، ډیر مصنوعي، مګر دا نظر څرګندوي. زموږ په غوښتنلیک کې، موږ د منطق پلي کولو لپاره ځنډول شوي خنډونه کاروو چې د شخړو د حل کولو مسولیت لري کله چې کاروونکي په ورته وخت کې په بورډ کې د شریک ویجټ شیانو سره کار کوي. د دې ډول محدودیتونو کارول موږ ته اجازه راکوي چې د غوښتنلیک کوډ یو څه ساده کړو.

په عموم کې، د خنډ ډول پورې اړه لري، پوسټګریس د دوی د چک کولو لپاره د ګرانولریت درې کچې لري: قطار، لیږد، او د بیان کچه.
پوسټګریس: بلوټ، pg_repack او ځنډول شوي خنډونه
سرچینه: begriffs

CHECK او NOT NULL تل د قطار په کچه چک کیږي؛ د نورو محدودیتونو لپاره، لکه څنګه چې د میز څخه لیدل کیدی شي، مختلف انتخابونه شتون لري. تاسو کولی شئ نور ولولئ دلته.

د لنډیز کولو لپاره، په یو شمیر حالتونو کې ځنډول شوي محدودیتونه د لوستلو وړ کوډ او لږ کمانډونه وړاندې کوي. په هرصورت، تاسو باید د ډیبګ کولو پروسې پیچلې کولو سره د دې لپاره پیسې ورکړئ، ځکه چې هغه شیبه چې خطا واقع کیږي او هغه شیبه چې تاسو یې په اړه ومومئ په وخت سره جلا کیږي. بله احتمالي ستونزه دا ده چې مهالویش کونکی ممکن تل د دې توان ونلري چې یو غوره پلان جوړ کړي که چیرې غوښتنه یو ځنډول شوی خنډ ولري.

د pg_repack ښه کول

موږ پوښلي چې ځنډول شوي خنډونه څه دي، مګر دوی زموږ له ستونزې سره څنګه تړاو لري؟ راځئ هغه تېروتنه په یاد وساتو چې موږ مخکې ترلاسه کړې وه:

$ ./pg_repack -t tablename -o id
INFO: repacking table "tablename"
ERROR: query failed: 
    ERROR: duplicate key value violates unique constraint "index_16508"
DETAIL:  Key (id, index)=(100500, 42) already exists.

دا واقع کیږي کله چې ډاټا د لاګ جدول څخه نوي میز ته کاپي کیږي. دا عجیب ښکاري ځکه چې ... د لاګ جدول کې ډاټا د سرچینې جدول کې د معلوماتو سره ژمنه ده. که دوی د اصلي میز محدودیتونه پوره کړي، دوی څنګه کولی شي په نوي کې ورته محدودیتونه سرغړونه وکړي؟

لکه څنګه چې دا معلومه شوه، د ستونزې ریښه د pg_repack په تیر مرحله کې ده، کوم چې یوازې شاخصونه رامینځته کوي، مګر محدودیتونه نه: زاړه میز یو ځانګړی محدودیت درلود، او نوي یې په ځای یو ځانګړی شاخص جوړ کړ.

پوسټګریس: بلوټ، pg_repack او ځنډول شوي خنډونه

دلته د یادولو وړ ده چې که چیرې محدودیت نورمال وي او ځنډول شوی نه وي ، نو د دې پرځای رامینځته شوی ځانګړی شاخص د دې محدودیت سره مساوي دی ، ځکه چې په پوسټګریس کې ځانګړي محدودیتونه د ځانګړي شاخص په رامینځته کولو سره پلي کیږي. مګر د ځنډول شوي خنډ په صورت کې، چلند یو شان نه دی، ځکه چې شاخص نشي ځنډول کیدی او تل د sql کمانډ اجرا کولو په وخت کې چک کیږي.

پدې توګه ، د ستونزې جوهر د چیک په "ځنډ" کې دی: په اصلي جدول کې دا د ژمنې په وخت کې پیښیږي ، او په نوي جدول کې کله چې د sql کمانډ اجرا کیږي. دا پدې مانا ده چې موږ باید ډاډ ترلاسه کړو چې چکونه په دواړو حالتونو کې یو شان ترسره کیږي: یا تل ځنډول کیږي، یا تل سمدستي.

نو موږ کوم نظرونه درلودل؟

ځنډول شوي ته ورته شاخص جوړ کړئ

لومړی نظر دا دی چې دواړه چکونه په فوري حالت کې ترسره کړئ. دا ممکن ډیری غلط مثبت محدودیتونه رامینځته کړي ، مګر که چیرې یو څو شتون ولري ، نو دا باید د کاروونکو کار اغیزه ونکړي ، ځکه چې دا ډول شخړې د دوی لپاره یو عادي حالت دی. دوی واقع کیږي، د بیلګې په توګه، کله چې دوه کاروونکي په ورته وخت کې د ورته ویجټ ترمیم پیل کړي، او د دویم کاروونکي پیرودونکي د معلوماتو ترلاسه کولو لپاره وخت نلري چې ویجټ دمخه د لومړي کارونکي لخوا د ترمیم لپاره بند شوی وي. په داسې حالت کې، سرور دویم کاروونکي ردوي، او د هغې مراجعین بدلونونه بیرته راولي او ویجټ بندوي. یو څه وروسته ، کله چې لومړی کارونکي ترمیم بشپړ کړي ، دوهم به معلومات ترلاسه کړي چې ویجټ نور بند شوی نه دی او د دې وړتیا به ولري چې خپل عمل تکرار کړي.

پوسټګریس: بلوټ، pg_repack او ځنډول شوي خنډونه

د دې لپاره چې ډاډ ترلاسه شي چې چکونه تل په غیر ځنډول شوي حالت کې وي، موږ د اصلي ځنډول شوي خنډ سره ورته یو نوی شاخص جوړ کړ:

CREATE UNIQUE INDEX CONCURRENTLY uk_tablename__immediate ON tablename (id, index);
-- run pg_repack
DROP INDEX CONCURRENTLY uk_tablename__immediate;

د ازموینې په چاپیریال کې، موږ یوازې یو څو تمه شوي غلطۍ ترلاسه کړې. بریالیتوب! موږ pg_repack بیا په تولید کې وګرځاوه او د کار په یو ساعت کې په لومړي کلستر کې 5 غلطۍ ترلاسه کړې. دا د منلو وړ پایله ده. په هرصورت، دمخه په دویم کلستر کې د غلطیو شمیر د پام وړ زیات شوی او موږ باید pg_repack ودروو.

ولې داسې وشول؟ د تېروتنې احتمال په دې پورې اړه لري چې څومره کاروونکي په ورته وخت کې د ورته ویجټونو سره کار کوي. په ښکاره ډول، په هغه وخت کې د نورو په پرتله په لومړي کلستر کې ذخیره شوي ډاټا سره خورا لږ رقابتي بدلونونه وو، د بیلګې په توګه. موږ یوازې "خوشحاله" وو.

نظر کار ونه کړ. په دې وخت کې، موږ دوه نور حلونه ولیدل: زموږ د غوښتنلیک کوډ بیا ولیکئ ترڅو د ځنډول شوي خنډونو سره توزیع کړي، یا د دوی سره کار کولو لپاره "درس" pg_repack. موږ دویمه برخه غوره کړه.

شاخصونه په نوي جدول کې د اصلي جدول څخه ځنډول شوي محدودیتونو سره بدل کړئ

د بیاکتنې موخه څرګنده وه - که اصلي جدول یو ځنډول شوی خنډ ولري، نو د نوي لپاره تاسو اړتیا لرئ چې دا ډول محدودیت رامینځته کړئ، نه شاخص.

زموږ د بدلونونو ازموینې لپاره، موږ یو ساده ازموینه لیکلې:

  • د ځنډول شوي محدودیت او یو ریکارډ سره میز؛
  • په یوه لوپ کې ډاټا داخل کړئ چې د موجوده ریکارډ سره ټکر کوي؛
  • یو تازه کړئ - ډاټا نور نه شخړه کوي؛
  • بدلونونه ژمن کړئ.

create table test_table
(
  id serial,
  val int,
  constraint uk_test_table__val unique (val) deferrable initially deferred 
);

INSERT INTO test_table (val) VALUES (0);
FOR i IN 1..10000 LOOP
  BEGIN
    INSERT INTO test_table VALUES (0) RETURNING id INTO v_id;
    UPDATE test_table set val = i where id = v_id;
    COMMIT;
  END;
END LOOP;

د pg_repack اصلي نسخه تل په لومړي داخل کې خرابه شوې، بدله شوې نسخه پرته له خطا کار کوي. غوره.

موږ تولید ته ځو او بیا د لاګ جدول څخه نوي ته د ډیټا کاپي کولو په ورته مرحله کې تېروتنه ترلاسه کوو:

$ ./pg_repack -t tablename -o id
INFO: repacking table "tablename"
ERROR: query failed: 
    ERROR: duplicate key value violates unique constraint "index_16508"
DETAIL:  Key (id, index)=(100500, 42) already exists.

کلاسیک وضعیت: هرڅه د ازموینې چاپیریال کې کار کوي ، مګر په تولید کې نه؟!

APPLY_COUNT او د دوو بستونو جنکشن

موږ د کوډ په لفظي ډول د کرښې په واسطه تحلیل پیل کړ او یو مهم ټکی مو وموندل: ډیټا د لاګ جدول څخه په بیچونو کې نوي ته لیږدول کیږي ، APPLY_COUNT ثابت د بیچ اندازه په ګوته کړه:

for (;;)
{
num = apply_log(connection, table, APPLY_COUNT);

if (num > MIN_TUPLES_BEFORE_SWITCH)
     continue;  /* there might be still some tuples, repeat. */
...
}

ستونزه دا ده چې د اصلي لیږد څخه ډاټا، په کوم کې چې ډیری عملیات په احتمالي توګه د خنډ څخه سرغړونه کولی شي، کله چې لیږدول کیږي، کولی شي د دوو بستونو په جنکشن کې پای ته ورسیږي - نیمایي کمانډونه به په لومړۍ بسته کې ژمن وي، او نور نیمایي په دویمه کې. او دلته، ستاسو په قسمت پورې اړه لري: که ټیمونه په لومړۍ بسته کې هیڅ شی سرغړونه نه کوي، نو هرڅه سم دي، مګر که دوی وکړي، یوه تېروتنه رامنځته کیږي.

APPLY_COUNT د 1000 ریکارډونو سره مساوي دی، کوم چې تشریح کوي چې ولې زموږ ازموینې بریالۍ وې - دوی د "بیچ جنکشن" قضیه نه پوښي. موږ دوه کمانډونه وکاروو - داخل کړئ او تازه کړئ، نو په سمه توګه د دوو کمانډونو 500 لیږدونه تل په یوه بسته کې ځای پر ځای شوي او موږ کومه ستونزه تجربه نه کړه. د دوهم تازه کولو اضافه کولو وروسته ، زموږ ترمیم کار بند کړ:

FOR i IN 1..10000 LOOP
  BEGIN
    INSERT INTO test_table VALUES (1) RETURNING id INTO v_id;
    UPDATE test_table set val = i where id = v_id;
    UPDATE test_table set val = i where id = v_id; -- one more update
    COMMIT;
  END;
END LOOP;

نو، راتلونکی دنده دا ده چې ډاډ ترلاسه کړئ چې د اصلي میز څخه ډاټا، کوم چې په یوه لیږد کې بدل شوی، په نوي میز کې هم په یوه لیږد کې پای ته رسیږي.

د بسته بندي کولو څخه انکار

او بیا موږ دوه حلونه درلودل. لومړی: راځئ چې په بشپړ ډول په بیچونو کې ویشل پریږدو او په یوه معامله کې ډیټا انتقال کړو. د دې حل ګټه د هغې سادگي وه - د اړتیا وړ کوډ بدلونونه لږ تر لږه وو (له لارې، په پخوانیو نسخو کې pg_reorg ورته ورته کار کاوه). مګر یوه ستونزه شتون لري - موږ یو اوږدمهاله معامله رامینځته کوو، او دا، لکه څنګه چې مخکې وویل شول، د نوي بلیټ رامینځته کیدو لپاره یو ګواښ دی.

دوهم حل ډیر پیچلی دی، مګر شاید ډیر درست: په لاګ جدول کې د لیږد پیژندونکي سره یو کالم جوړ کړئ چې میز ته یې معلومات اضافه کړي. بیا، کله چې موږ ډاټا کاپي کوو، موږ کولی شو دا د دې ځانګړتیا له مخې ګروپ کړو او ډاډ ترلاسه کړو چې اړوند بدلونونه یوځای لیږدول شوي. بسته به د څو لیږدونو (یا یو لوی) څخه جوړه شي او د هغې اندازه به توپیر ولري پدې پورې اړه لري چې پدې معاملو کې څومره معلومات بدل شوي. دا مهمه ده چې په یاد ولرئ چې له هغه وخته چې د مختلفو معاملو ډاټا په تصادفي ترتیب کې د لاګ جدول ته ننوځي، نو دا به نور امکان ونلري چې په ترتیب سره یې ولولي، لکه څنګه چې مخکې وو. د tx_id لخوا د فلټر کولو سره د هرې غوښتنې لپاره seqscan خورا ګران دی ، یو شاخص ته اړتیا ده ، مګر دا به د دې تازه کولو د سر له امله میتود ورو کړي. په عموم کې، د تل په څیر، تاسو اړتیا لرئ یو څه قرباني کړئ.

نو، موږ پریکړه وکړه چې د لومړي اختیار سره پیل وکړو، ځکه چې دا خورا ساده دی. لومړی، دا اړینه وه چې پوه شي چې آیا اوږده معامله به ریښتینې ستونزه وي. څرنګه چې د زاړه میز څخه نوي ته د معلوماتو اصلي لیږد هم په یوه اوږده راکړه ورکړه کې واقع کیږي، پوښتنه بدله شوه "موږ به دا معامله څومره زیاته کړو؟" د لومړي لیږد موده په عمده توګه د میز په اندازې پورې اړه لري. د نوي وخت موده پدې پورې اړه لري چې څومره بدلونونه د ډیټا لیږد پرمهال په جدول کې راټولیږي ، د بیلګې په توګه. د بار په شدت باندې د pg_repack چلول د لږترلږه خدماتو بار په وخت کې پیښ شوي، او د بدلونونو حجم د میز د اصلي اندازې په پرتله په غیر متناسب ډول کوچنی و. موږ پریکړه وکړه چې موږ کولی شو د نوي لیږد وخت غفلت وکړو (د پرتله کولو لپاره، په اوسط ډول دا 1 ساعت او 2-3 دقیقې دی).

تجربې مثبتې وې. تولید هم پیل کړئ. د وضاحت لپاره، دلته یو انځور دی چې د چلولو وروسته د ډیټابیسونو څخه یو اندازه لري:

پوسټګریس: بلوټ، pg_repack او ځنډول شوي خنډونه

څرنګه چې موږ د دې حل څخه په بشپړه توګه مطمین یو، موږ د دویم پلي کولو هڅه نه ده کړې، مګر موږ د تمدید پراختیا کونکو سره د دې په اړه د بحث کولو امکان په پام کې نیسو. زموږ اوسنی بیاکتنه ، له بده مرغه ، لاهم د خپرولو لپاره چمتو نه ده ، ځکه چې موږ یوازې د ځانګړي ځنډول شوي محدودیتونو سره ستونزه حل کړې ، او د بشپړ پیچ لپاره دا اړینه ده چې د نورو ډولونو ملاتړ چمتو کړو. موږ هیله لرو چې په راتلونکي کې دا کار وکړو.

شاید تاسو پوښتنه لرئ، ولې موږ حتی د pg_repack تعدیل سره پدې کیسه کې ښکیل شو، او د مثال په توګه، د دې انلاګونه نه کاروو؟ په ځینو وختونو کې موږ هم په دې اړه فکر کاوه، مګر د پخوا څخه د کارولو مثبتې تجربې، پرته له ځنډه خنډونو میزونو کې، موږ هڅول چې د ستونزې په ماهیت پوه شو او حل یې کړو. سربیره پردې ، د نورو حلونو کارول هم د ازموینو ترسره کولو لپاره وخت ته اړتیا لري ، نو موږ پریکړه وکړه چې لومړی به هڅه وکړو پدې کې ستونزه حل کړو ، او که موږ پوه شو چې موږ دا په مناسب وخت کې نشو کولی نو بیا به موږ انالوګونو ته ګورو. .

موندنو

هغه څه چې موږ کولی شو د خپلې تجربې پراساس وړاندیز وکړو:

  1. خپل پړسوب څارنه وکړئ. د څارنې معلوماتو پراساس ، تاسو کولی شئ پوه شئ چې آټوواکوم څومره ښه تنظیم شوی.
  2. د منلو وړ کچې د غوړ ساتلو لپاره آټوواکوم تنظیم کړئ.
  3. که چیرې پړسوب لاهم وده کوي او تاسو نشئ کولی د بکس څخه بهر وسیلو په کارولو سره بریالي شئ ، د بهرني توسیع کارولو څخه مه ویره مه کوئ. اصلي شی دا ده چې هر څه ښه ازموینه وکړئ.
  4. د خپلو اړتیاو سره سم د بهرني حلونو بدلولو کې مه ویره مه کوئ - ځینې وختونه دا ستاسو د خپل کوډ بدلولو په پرتله خورا مؤثره او حتی اسانه کیدی شي.

سرچینه: www.habr.com

Add a comment