پارتیشنپرونینگ در پستگرس بدون کلید پارتیشن
خلاصهٔ کاملتر
به گفتهٔ نویسنده، ارزشمندترین چیز تو جدولهای پارتیشنبندیشده همین پرونینگه: توانایی دیتابیس برای حذف کامل یه پارتیشن بر اساس شرط کوئری. حکمت رایج میگه این فقط وقتی ممکنه که روی کلید پارتیشن فیلتر کنی، و دقیقاً همین باعث میشه انتخاب کلید درست اینقدر سخت باشه. ادعای مقاله اینه که با چندتا ترفند، اگه دادههات الگوی خاصی داشته باشن، میشه روی ستونهای غیرکلیدی هم پرونینگ گرفت.
مثال کار یه جدول رویداده: یه سایت پرکاربر که رویدادها رو لاگ میکنه و برای اینکه رویدادها زمینه داشته باشن، تو قالب نشست گروهبندیشون میکنه.
CREATE TABLE event (
id BIGINT GENERATED ALWAYS AS IDENTITY,
timestamp TIMESTAMPTZ NOT NULL,
session_id BIGINT NOT NULL,
type TEXT NOT NULL,
data JSONB
) PARTITION BY RANGE (timestamp);چون بیشتر کوئریها فقط یه بازهٔ زمانی خاص رو میخوان، برای هر سال یه پارتیشن ساخته میشه. حالا کوئری روی بازهٔ دسامبر ۲۰۲۵ رو که EXPLAIN بگیری، خروجی فقط Seq Scan on event_y2025 رو نشون میده و پارتیشن ۲۰۲۶ اصلاً لمس نشده. این همون پرونینگه.
ولی یه کوئری رایج دیگه هم هست: پیدا کردن همهٔ رویدادهای یه نشست خاص. اینجا پلن اجرا یه Append روی هر دو پارتیشن میشه، چون دیتابیس هیچ راهی برای حذف پارتیشن نداره. ساختن ایندکس روی session_id هم مسئله رو حل نمیکنه: تنها فرقش اینه که بهجای اسکن ترتیبی، روی هر پارتیشن از ایندکس استفاده میشه. با دو پارتیشن قابل تحمله، ولی با صد پارتیشن انگار داری صد تا جدول رو کوئری میکنی.
دلیل فنیاش اینه که ایندکس روی جدول پارتیشنشده در پستگرس local ـه: روی هر پارتیشن یه ایندکس جدا ساخته میشه. جایگزینش ایندکس global ـه، یعنی یه ایندکس واحد روی چند پارتیشن، که به گفتهٔ نویسنده پستگرس تا نسخهٔ ۱۹ هم ازش پشتیبانی نمیکنه — بحثش تو فهرست پستی pgsql-hackers تا سال ۲۰۰۹ عقب میره. نبود ایندکس سراسری اعمال یکتایی روی ستونهای غیرکلیدی رو هم سخت میکنه.
اینجا نویسنده میگه به سقف کاری که دیتابیس بهتنهایی بلده رسیدی و باید از دانش دامنهات استفاده کنی. سه ویژگی این داده کلیدیان: جدول فقط-افزودنیه و رویدادها تغییرناپذیرن، شناسهٔ نشستها ترتیبی تولید میشن، و نشستها کوتاهعمرن — معمولاً چند دقیقه تا چند ساعت. یعنی session_id همبستگی قوی با timestamp داره.
برای دیدنش کافیه کمینه و بیشینهٔ شناسهٔ نشست رو در هر پارتیشن دربیاری:
SELECT tableoid::regclass, MIN(session_id), MAX(session_id)
FROM event GROUP BY 1 ORDER BY 1;خروجی نشون میده شناسههای ۱ تا ۴۳۱۹ فقط تو پارتیشن ۲۰۲۵ هستن و ۴۳۲۱ تا ۱۰۰۰۰ فقط تو ۲۰۲۶ — یعنی یه بازهٔ روشن و مجزا برای هر پارتیشن. سؤال بعدی اینه که چطور این دانش رو به دیتابیس منتقل کنی، چون بهینهساز بدون نگاه کردن به خود داده تصمیم میگیره و تنها چیزی که دستشه آمارههاست. ادامهٔ مقاله سراغ همین میره: پارامتر constraint_exclusion، مدیریت دادههای پرت، و مسئلهٔ فاصلهها و جزیرهها.
نکات کلیدی:
- پرونینگ یعنی حذف کامل یه پارتیشن از مسیر اجرا، نه فقط سریعتر خوندنش
- فیلتر روی ستون غیرکلیدی همهٔ پارتیشنها رو لمس میکنه، حتی وقتی ایندکس داری
- ایندکس روی جدول پارتیشنشده local ـه؛ پستگرس تا نسخهٔ ۱۹ ایندکس global نداره
- اگه ستون غیرکلیدی با کلید پارتیشن همبستگی قوی داشته باشه، هر پارتیشن بازهٔ مشخصی میگیره
- سه شرط این ترفند: جدول فقط-افزودنی، شناسهٔ ترتیبی، و رکوردهای کوتاهعمر




