تا اینجا با ساختار فیزیکی ذخیره فایلها در PostgreSQL آشنا شدهایم و میدانیم که:
$PGDATA/base/<database_oid>/<file_identifier>
pg_class.oid == filename on disk
اما این فقط در ابتدای عمر جدول درست است.
در بسیاری از عملیاتها PostgreSQL فایل فیزیکی جدول را عوض میکند، اما هویت منطقی جدول تغییر نمیکند.
در اینجا یک مفهوم کلیدی وارد میشود:
ستونی در جدول سیستمی pg_class که مشخص میکند:
فایل فیزیکی فعلی این جدول روی دیسک چیست؟
بنابراین:
| مفهوم | نقش | تغییر میکند؟ |
|---|---|---|
| OID | هویت منطقی جدول در کاتالوگ | ❌ تقریباً هرگز |
| relfilenode | شناسه فایل فیزیکی فعلی | ✅ گاهی تغییر میکند |
پس اگر PostgreSQL فایل جدول را بازنویسی کند:
بنابراین برای پیدا کردن فایل واقعی جدول روی دیسک، همیشه باید relfilenode را بررسی کنیم، نه OID.
هر جدول دو هویت دارد:
pg_class.oid
شناسه دائمی جدول در کاتالوگ سیستم
این شناسه:
pg_class.relfilenode
شناسه فایل واقعی روی دیسک
این شناسه:
چند دستور مهم باعث بازنویسی کامل جدول میشوند:
در همه اینها:
فایل جدید ساخته میشود
relfilenode عوض میشود
OID ثابت میماند
CREATE DATABASE relfilenode_workshop;
\c relfilenode_workshop
CREATE TABLE employees (
id serial PRIMARY KEY,
name text,
salary numeric,
updated_at timestamp default now()
);
SELECT oid, relfilenode, relname
FROM pg_class
WHERE relname='employees';
SELECT pg_relation_filepath('employees');
در ابتدای ایجاد جدول معمولاً:
oid = relfilenode
INSERT INTO employees(name,salary)
SELECT 'emp'||i, random()*100000
FROM generate_series(1,100000) i;
دوباره relfilenode را بررسی کنید.
نتیجه:
✔ تغییری نمیکند
✔ فقط داده به فایل موجود اضافه میشود
دستور DELETE برای حذف سطرهای مشخص یا همه سطرهای جدول بر اساس شرط (یا بدون شرط) استفاده میشود.
این دستور رکوردها را فیزیکی حذف نمیکند، بلکه آنها را طبق MVCC بهصورت «حذفشده» علامتگذاری میکند.
در نتیجه:
DELETE FROM employees;
نتیجه:
چرا؟
چون PostgreSQL فقط رکوردها را dead mark میکند.
دستور TRUNCATE برای حذف سریع و کامل همه رکوردهای یک جدول استفاده میشود.
این دستور بهجای حذف تکتک سطرها، فایل فیزیکی جدول را با یک فایل جدید و خالی جایگزین میکند، بنابراین:
TRUNCATE employees;
نتیجه فوری:
✔ فایل جدید ساخته میشود
✔ relfilenode تغییر میکند
✔ جدول کاملاً خالی
✔ فضای دیسک آزاد
این عملیات در واقع:
drop file + create new empty file
اما هویت منطقی جدول حفظ میشود.
| ویژگی | DELETE | TRUNCATE |
|---|---|---|
| حذف منطقی | بله | خیر |
| MVCC | دارد | ندارد |
| فایل جدید | خیر | بله |
| relfilenode | ثابت | تغییر |
| سرعت | کندتر | بسیار سریع |
نکته مهم:
وقتی فایل جدول عوض شود، ایندکسها هم باید بازسازی شوند.
بنابراین در TRUNCATE و VACUUM FULL:
relfilenode جدول تغییر میکند
relfilenode ایندکسها هم تغییر میکند
هدف VACUUM FULL:
مراحل داخلی:
در نتیجه:
✔ relfilenode جدید
✔ جدول فشرده
✔ بدون dead tuple
ایجاد bloat:
UPDATE employees
SET salary = salary * 1.1;
اجرای VACUUM FULL:
VACUUM FULL employees;
سپس:
SELECT oid, relfilenode
FROM pg_class
WHERE relname='employees';
مشاهده میکنید:
relfilenode تغییر کرده
PostgreSQL بین هویت منطقی و هویت فیزیکی تفکیک کامل دارد.
این طراحی مزایای بزرگی دارد:
✔ امکان بازنویسی جدول بدون شکستن وابستگیها
✔ امکان بهینهسازی ذخیرهسازی
✔ امکان حذف bloat
✔ حفظ integrity سیستم
محتوای ویدئویی کارگاه در بخش زیر قابل مشاهده است.