Antipatterns PostgreSQL: مبارزه با انبوهی از "مردگان"

ویژگی های مکانیسم های داخلی PostgreSQL به آن اجازه می دهد در برخی موقعیت ها بسیار سریع و در برخی دیگر "خیلی سریع" نباشد. امروز ما بر روی یک مثال کلاسیک از تضاد بین نحوه کار یک DBMS و کاری که توسعه دهنده با آن انجام می دهد تمرکز خواهیم کرد - به روز رسانی در مقابل اصول MVCC.

داستان کوتاه از مقاله عالی:

هنگامی که یک ردیف با دستور UPDATE اصلاح می شود، در واقع دو عملیات انجام می شود: DELETE و INSERT. که در نسخه فعلی رشته xmax برابر با تعداد تراکنشی است که UPDATE را انجام داده است. سپس ایجاد می شود یک نسخه جدید همان خط؛ مقدار xmin آن با مقدار xmax نسخه قبلی مطابقت دارد.

مدتی پس از تکمیل این تراکنش، نسخه قدیمی یا جدید بسته به COMMIT/ROOLBACK، شناخته خواهد شد "مرده" (تپل های مرده) هنگام عبور VACUUM مطابق جدول و پاک شده است.

Antipatterns PostgreSQL: مبارزه با انبوهی از "مردگان"

اما این بلافاصله اتفاق نمی افتد، اما مشکلات مربوط به "مرده" را می توان خیلی سریع به دست آورد - با تکرار یا به روز رسانی انبوه سوابق در یک میز بزرگ و کمی بعد با همین وضعیت روبرو خواهید شد VACUUM نمی تواند کمک کند.

شماره 1: من دوست دارم آن را جابجا کنم

فرض کنید روش شما روی منطق تجاری کار می کند، و ناگهان متوجه می شود که لازم است فیلد X را در یک رکورد به روز کنید:

UPDATE tbl SET X = <newX> WHERE pk = $1;

سپس، با پیشرفت اجرا، معلوم می شود که فیلد Y نیز باید به روز شود:

UPDATE tbl SET Y = <newY> WHERE pk = $1;

... و سپس Z - چرا وقت را صرف چیزهای بی اهمیت کنیم؟

UPDATE tbl SET Z = <newZ> WHERE pk = $1;

اکنون چند نسخه از این رکورد در پایگاه داده داریم؟ بله، 4 قطعه! از این میان، یکی مربوط است، و 3 مورد باید بعد از شما توسط [خودکار] جاروبرقی تمیز شوند.

اینجوری نکن! استفاده کنید به روز رسانی تمام فیلدها در یک درخواست - تقریباً همیشه منطق روش را می توان به صورت زیر تغییر داد:

UPDATE tbl SET X = <newX>, Y = <newY>, Z = <newZ> WHERE pk = $1;

شماره 2: استفاده از آن متمایز است، لوک!

بنابراین، شما هنوز هم می خواستید بسیاری از رکوردها را در یک جدول به روز کنید (مثلاً در حین استفاده از یک اسکریپت یا مبدل). و چیزی شبیه به این در فیلمنامه وجود دارد:

UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2;

درخواست تقریباً در این فرم اغلب و تقریباً همیشه برای پر کردن یک فیلد خالی جدید، بلکه برای تصحیح برخی از اشتباهات در داده ها رخ می دهد. در عین حال، خودش صحت داده های موجود به هیچ وجه در نظر گرفته نمی شود - اما بیهوده! یعنی رکورد بازنویسی می‌شود، حتی اگر دقیقاً حاوی آنچه می‌خواستیم باشد - اما چرا؟ بیایید درستش کنیم:

UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM <newX>;

بسیاری از مردم از وجود چنین اپراتور فوق العاده ای آگاه نیستند، بنابراین در اینجا یک برگه تقلب ارائه شده است IS DISTINCT FROM و سایر عملگرهای منطقی برای کمک به:
Antipatterns PostgreSQL: مبارزه با انبوهی از "مردگان"
... و کمی در مورد عملیات در مجتمع ROW()-اصطلاحات:
Antipatterns PostgreSQL: مبارزه با انبوهی از "مردگان"

شماره 3: من معشوقه ام را با بلاک کردن می شناسم

در حال راه اندازی هستند دو فرآیند موازی یکسان، که هر کدام سعی می کند ورودی "در حال انجام" را علامت گذاری کند:

UPDATE tbl SET processing = TRUE WHERE pk = $1;

حتی اگر این فرآیندها واقعاً کارها را مستقل از یکدیگر انجام دهند، اما در همان شناسه، مشتری دوم در این درخواست تا زمانی که اولین تراکنش کامل شود، "قفل" خواهد شد.

راه حل شماره 1: کار به قبلی کاهش می یابد

بیایید دوباره آن را اضافه کنیم IS DISTINCT FROM:

UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;

در این فرم، درخواست دوم به سادگی چیزی را در پایگاه داده تغییر نمی دهد، همه چیز در حال حاضر همانطور که باید باشد - بنابراین، مسدود کردن رخ نخواهد داد. در مرحله بعد، واقعیت "یافتن نشدن" رکورد را در الگوریتم اعمال شده پردازش می کنیم.

راه حل شماره 2: قفل های مشاوره ای

یک موضوع بزرگ برای یک مقاله جداگانه، که در آن می توانید در مورد آن بخوانید روش‌های کاربرد و "ریک" مسدود کردن توصیه‌ای.

راه حل شماره 3: تماس های احمقانه

اما این دقیقاً همان چیزی است که باید برای شما اتفاق بیفتد کار همزمان با همان رکورد? یا مثلاً الگوریتم های فراخوانی منطق کسب و کار در سمت مشتری را به هم ریخته اید؟ و اگر به آن فکر کنید؟..

منبع: www.habr.com

اضافه کردن نظر