در دنیای پایگاه دادههای مدرن، عملکرد و کارایی اغلب به جزئیات پنهان زیر سطح دادهها بستگی دارد. در PostgreSQL، جدولها تنها فایلهای داده اصلی نیستند که ردیفها را ذخیره میکنند؛ بلکه چند فایل جانبی کوچک وجود دارند که نقش حیاتی در سرعت و بهینهسازی عملیات دارند. دو نمونه کلیدی از این فایلها Free Space Map (_fsm) و Visibility Map (_vm) هستند.
تصور کنید جدول شما یک ساختمان است: صفحات داده، واحدهای آپارتمان هستند و ردیفها ساکنان. FSM نقش یک «مشاور املاک دقیق» را بازی میکند، همیشه میداند کدام صفحات فضای خالی دارند و به PostgreSQL کمک میکند تا هنگام درج ردیفهای جدید، بدون هدر دادن فضا، سریعاً محل مناسب را پیدا کند. از سوی دیگر، VM مانند یک «لیست VIP» عمل میکند و به سیستم میگوید کدام صفحات کاملاً قابل مشاهده و پایدار هستند؛ این اطلاعات به Index-Only Scan و VACUUM اجازه میدهد تا با صرف حداقل I/O، عملیات خود را انجام دهند.
در این کارگاه، ما به بررسی این دو فایل جانبی میپردازیم، نحوه عملکرد آنها را میآموزیم و با ابزارهای داخلی PostgreSQL روشهای پایش و تحلیل آنها را تمرین خواهیم کرد. شما با درک عمیق این فایلها، نه تنها قادر خواهید بود عملکرد جداول خود را بهینه کنید، بلکه میتوانید مشکلات بالقوه مربوط به رشد غیرکارآمد فایلها و تراکنشهای طولانی را سریعتر شناسایی کنید.
هر جدول (و ایندکس) در PostgreSQL یک فایل اصلی داده دارد که ردیفها را ذخیره میکند. در کنار آن، یک Free Space Map با نام <relfilenode>_fsm وجود دارد که میزان فضای آزاد موجود در هر صفحه ۸ کیلوبایتی جدول را ثبت میکند.
چرا به FSM نیاز داریم؟
هنگامی که یک ردیف جدید وارد جدول میشود، PostgreSQL باید صفحهای پیدا کند که فضای کافی برای ذخیره آن داشته باشد. بدون FSM، پایگاه داده باید یا:
FSM مانند یک فهرست سریع عمل میکند و صفحات مناسب برای درج ردیف جدید را مشخص میکند، بدون آنکه فضای موجود هدر برود.
FSM به صورت یک درخت از صفحات ۸ کیلوبایتی ذخیره میشود:
این روش، اطلاعات فضای آزاد را فشرده میکند و همچنان برای انتخاب صفحه مناسب کافی است.
pg_freespacemapابتدا یک جدول تست ایجاد و مقداری داده وارد میکنیم:
CREATE TABLE fsm_test (
id serial,
data text
);
INSERT INTO fsm_test (data)
SELECT 'some text'
FROM generate_series(1, 1000);
اکنون افزونه pg_freespacemap را فعال میکنیم:
CREATE EXTENSION IF NOT EXISTS pg_freespacemap;
و فضای آزاد جدول را بررسی میکنیم:
SELECT * FROM pg_freespace('fsm_test');
خروجی مشابه زیر خواهد بود:
blkno | avail
-------+-------
۰ | ۰
۱ | ۰
۲ | ۰
... | ...
۵ | ۲۵۹۸
avail میزان فضای آزاد (بر حسب بایت) برای هر صفحه است.حالا چند ردیف حذف میکنیم تا ببینیم FSM فوراً بهروز نمیشود:
DELETE FROM fsm_test WHERE id % 3 = 0;
SELECT * FROM pg_freespace('fsm_test');
مقدار فضای آزاد هنوز تغییر نکرده است. علت: FSM عمدتاً توسط VACUUM بهروزرسانی میشود.
اجرای یک VACUUM دستی:
VACUUM fsm_test;
SELECT * FROM pg_freespace('fsm_test');
اکنون مقدار avail برای صفحاتی که ردیف حذف شدهاند، افزایش یافته است و FSM از فضای آزاد آگاه شده است.
pageinspectافزونه pageinspect امکان مشاهده صفحات خام FSM را میدهد:
CREATE EXTENSION IF NOT EXISTS pageinspect;
ابتدا اندازه فایل FSM (تعداد صفحات) را بررسی کنید:
SELECT relname, relfilenode
FROM pg_class
WHERE relname = 'fsm_test';
حالا اولین صفحه FSM را بررسی کنید:
SELECT * FROM fsm_page_contents(get_raw_page('fsm_test', 'fsm', 0));
خروجی یک نمایش متنی از گرههای ذخیره شده در آن صفحه است:
۰: leaf: avg 150, max 255, nodes ...
برای درک عمیقتر، میتوانید توضیحات منبع در
src/backend/storage/freespace/READMEرا مطالعه کنید.
نگرش کلیدی: FSM یک بهینهسازی عملکرد است. اگر فکر میکنید فضای جدول بهدرستی استفاده نمیشود، FSM را بررسی و VACUUM را اجرا کنید.
Visibility Map یک فایل کمکی دیگر (<relfilenode>_vm) است که برای هر صفحه دو بیت ذخیره میکند:
چرا VM مهم است؟
VM یک bitmap ساده است که در صفحات ۸ کیلوبایتی ذخیره میشود. برای جدولی با N صفحه، حجم VM تقریباً N / (8 * 8192) صفحه است – بسیار کوچک نسبت به حجم جدول.
pg_visibilityافزونه را فعال کنید:
CREATE EXTENSION IF NOT EXISTS pg_visibility;
و VM جدول تست را بررسی کنید:
SELECT * FROM pg_visibility_map('fsm_test');
خروجی شامل شماره صفحه و دو پرچم boolean (all_visible, all_frozen) است.
اجرای VACUUM باعث تنظیم پرچمها میشود:
VACUUM fsm_test;
SELECT * FROM pg_visibility_map('fsm_test');
اکثر صفحات اکنون all_visible خواهند بود.
یک ردیف روی صفحهای که all-visible است را بهروزرسانی کنید:
UPDATE fsm_test SET data = 'modified' WHERE id = 1;
SELECT * FROM pg_visibility_map('fsm_test') WHERE blkno = 0;
all_visible بلافاصله پاک میشود (hint است، WAL ثبت نمیشود)EXPLAIN (ANALYZE, BUFFERS) بررسی کنید؛ اگر Heap Fetches: 0 مشاهده کردید، VM به بهینه شدن پرسوجو کمک کرده است.این فایلها همیشه کمی عقبتر از جدول هستند و این طبیعی است؛ چون برای بهینهسازی، نه صحت داده، استفاده میشوند.
SELECT count(*) FROM pg_freespace('fsm_test') WHERE avail = 0;
SELECT count(*) FROM pg_visibility_map('fsm_test') WHERE all_visible;
pg_stat_user_tables: ستونهایی مانند n_dead_tup, last_vacuum, vacuum_count به درک وضعیت کمک میکنندautovacuum_vacuum_scale_factor و autovacuum_vacuum_threshold باید تنظیم شوندpg_freespacemap و pg_visibility تنها خواندن داده دارند و در تشخیص مشکلات بسیار مفید هستندVACUUM FULL یا CLUSTER بازسازی کرد (با احتیاط)📹 محتوای ویدئویی کارگاه در بخش زیر قابل مشاهده است.