هزینه UUIDv4 در Postgres؛ افت سرعت INSERT وقتی index از حافظه بزرگ‌تر می‌شود

چرا مهم است

اگر برای primary key از UUIDv4 استفاده می‌کنی، نتیجه یک آزمایش کوچک ممکن است هزینه رشد جدول را نشان ندهد. در این بررسی، تفاوت اصلی وقتی ظاهر شد که index از حافظه بزرگ‌تر شد؛ هزینه write-ahead log هم جداگانه افزایش یافت.

قبل از خواندن، این‌ها را بدان۵ مفهوم
primary key

ستون یا مجموعه‌ای از ستون‌ها که هر ردیف جدول را به‌صورت یکتا مشخص می‌کند و مقدار تکراری یا NULL نمی‌پذیرد.

بیشتر درباره این مفهوم

index

ساختاری کمکی در database برای پیدا کردن ردیف‌ها بدون بررسی همه آن‌ها؛ با تغییر داده‌های مرتبط، این ساختار هم باید به‌روز شود.

بیشتر درباره این مفهوم

transaction

واحدی از کار در database که یک یا چند عملیات را در بر می‌گیرد و تغییرات آن با هم نهایی یا لغو می‌شوند.

بیشتر درباره این مفهوم

نمایش همه (۵)
write-ahead log

گزارشی از تغییرات database که پیش از نوشته‌شدن تغییرات در فایل‌های اصلی ثبت می‌شود و برای بازیابی به کار می‌رود؛ معمولاً WAL نامیده می‌شود.

بیشتر درباره این مفهوم

checkpoint

نقطه‌ای در روند کار database که نوشتن تغییرات حافظه روی فضای ذخیره‌سازی را هماهنگ می‌کند و مبنایی برای بازیابی فراهم می‌سازد.

بیشتر درباره این مفهوم

Nikolay Samokhvalov در آزمایشی روی Postgres،؜ هزینه انتخاب UUIDv4 به‌عنوان primary key را با UUIDv7 و int8 مقایسه کرده است. نتیجه اصلی به اندازه index نسبت به حافظه بستگی دارد: تا وقتی index در حافظه جا می‌شود، تفاوت نرخ INSERT کم است؛ اما با عبور از این محدوده، هزینه کلید تصادفی آشکار می‌شود.

این آزمایش با Postgres 18.6،؜ شانزده client و یک INSERT تک‌ردیفی در هر transaction انجام شده است. سه جدول، schema و جریان INSERT یکسان داشتند و فقط primary key آن‌ها متفاوت بود. هر جدول علاوه بر primary key،؜ روی user_id و created_at هم index داشت؛ بنابراین حتی جدول‌های دارای کلید مرتب نیز هزینه یک index با INSERT تصادفی را می‌پرداختند. نسبت‌های اصلی عملکرد، بین کلیدها روی یک server محاسبه شده‌اند.

در حالتی با shared_buffers برابر ۱ GiB و سقف حافظه ۳ GiB،؜ افت UUIDv4 از حدود ۲۶ میلیون ردیف شروع شد؛ جایی که index مربوط به primary key از shared_buffers بزرگ‌تر شد. در ۱۰۰ میلیون ردیف، نرخ INSERT با UUIDv4 به ۶۲ تا ۶۹ درصد نرخ کلید مرتب روی همان server رسید. توضیح گزارش این است که هر INSERT با UUIDv4 به یک leaf تصادفی می‌رود و پس از عبور از سقف حافظه، تقریباً به یک خواندن buffer و یک نوشتن صفحه خارج‌شده از حافظه نیاز دارد.

هزینه write-ahead log نیز جداگانه اندازه‌گیری شد. در بازه ۹۰ تا ۱۰۰ میلیون ردیف، UUIDv4 به‌ازای هر ردیف ۱٫۵ تا ۱٫۹ برابر کلید مرجع روی همان server،؜ write-ahead log تولید کرد. گزارش این تفاوت را به تعداد leaf‌هایی مرتبط می‌داند که در هر چرخه checkpoint لمس و دوباره به‌صورت تصویر کامل ثبت می‌شوند.

Postgres 18 تابع uuidv7() را دارد. گزارش توصیه می‌کند UUIDv7 داخل Postgres ساخته شود: در آزمایشی با اختلاف ساعت client‌ها در محدوده مثبت و منفی ۶۰ ثانیه، index فقط ۶۹ درصد پر بود و ۴۵ درصد leaf‌ها خارج از ترتیب بودند. همچنین ORDER BY id DESC LIMIT 100 روی UUIDv4،؜ صد مقدار تصادفی با بزرگ‌ترین مقدارها را برمی‌گرداند، نه لزوماً تازه‌ترین ردیف‌ها.

نکته کلیدی

هنگام مقایسه کلیدها، اندازه index نسبت به حافظه را هم در نظر بگیر و نسبت‌ها را روی یک server بسنج. اگر UUIDv7 را انتخاب می‌کنی، هشدار گزارش درباره اختلاف ساعت client‌ها و توصیه تولید آن داخل Postgres را به خاطر بسپار.

خواندن مقاله اصلی (در زبانه‌ی جدید باز می‌شود)
برچسب‌ها (۳)