پرش به محتوای اصلی

آموزش یک مدل 4B برای تولید 81٪ طرح های جستجو سریعتر از Postgres

هکرنیوز۱۴۰۵ شهریور ۲۵, چهارشنبه، ساعت ۲۲:۲۰حدود 18 دقیقه مطالعه

آدرس مقاله: https://rohanbansal.com/qorl آدرس نظرات: https://news.ycombinator.com/item?id=49731285 امتیاز: 297 # نظرات: 54

لیس و همکاران این سوال را دقیقا در سال 2015 پرسیدند. سپس 10 سال بعد دوباره آن را پرسیدند.

علیرغم حجم عظیمی از تحقیقات که یک دهه از اکتشاف اولیه آنها می گذرد، آنها دریافتند که بهینه سازهای پرس و جو همچنان چیزهای زیادی را به جا می گذارند.

وقتی برای اولین بار از این موضوع مطلع شدم شگفت زده شدم. یک پایگاه داده Postgres باید همه چیز را در مورد چیزهایی که در جداول آن وجود دارد بداند، نه؟ چقدر میتونه سخت باشه

همانطور که معلوم است: بسیار سخت است. در واقع، یک وظیفه خاص که یک بهینه‌ساز پرس و جو باید انجام دهد، یعنی سفارش دادن، NP-hard است.

بنابراین بهینه سازهای پرس و جو سخت هستند. چیزی که سخت نیست، تأیید این است که آیا طرح پرس و جو که یک بهینه ساز انتخاب می کند خوب است یا خیر. به زبان ساده، یک بهینه ساز پرس و جو خوب، طرح هایی را تولید می کند که سریع اجرا می شوند، و یک بهینه ساز بد، برنامه های آهسته تولید می کند. مدل‌های زبان به‌ویژه در یادگیری نحوه انجام وظایف با خروجی‌های به راحتی قابل تأیید هستند. از آنجا که یک محور واحد برای بهینه سازی وجود دارد - زمان اجرای یک پرس و جو - این مشکل به زیبایی به تقویت رفتارهایی کاهش می یابد که یک مدل را برای تولید طرح های پرس و جو سریعتر راهنمایی می کند.

آنچه در زیر می آید تجزیه و تحلیل آزمایشی است که برای بررسی این سوال انجام دادم: آیا می توان یک مدل کوچک و وزن باز را از طریق تنظیم دقیق نظارت شده (SFT) و یادگیری تقویتی عاملی (RL) برای تولید طرح های پرس و جو Postgres که طرح های پیش فرض Postgres را شکست داد، پس از آموزش آموزش داد؟

پاسخ به سوال ما یک بله قاطع است. نکات برجسته عبارتند از:

برش زیر از مجموعه داده های IMDb را در نظر بگیرید:

فرض کنید من سعی می کنم به این سوال پاسخ دهم: "کدام شرکت های ژاپنی بیشترین عناوین را در دهه 2000 منتشر کردند؟" ممکن است پرس و جو زیر را بنویسیم:

اجرای این پرس و جو 10 شرکت ژاپنی را با تعداد عناوینی که بین سال‌های 2000 تا 2009 با آنها مرتبط بوده‌اند، به‌دست می‌آورد که از بالاترین به پایین‌ترین مرتبه‌سازی شده‌اند.

مسیری که Postgres برای به دست آوردن این داده‌ها برای ما طی کرد، یک نتیجه‌گیری پیش‌فرض نیست، و همه چیز با آنچه ما محمولات انتخابی می‌نامیم (یعنی شرایط فیلتر در یک بند WHERE) مرتبط است.

برای نشان دادن این موضوع، بیایید همان درخواست خود را بدون فیلتر شرکت ژاپنی یا فیلتر محدوده تاریخ تصور کنیم:

mc فقط می تواند با cn از طریق mc.company_id = cn.id بپیوندد و t فقط می تواند با mc از طریق t.id = mc.movie_id بپیوندد.

اگر جابجایی را در نظر بگیریم، این محدودیت‌ها دو درخت ایجاد می‌کنند. در این مورد، ما این کار را نمی کنیم زیرا بر اندازه روابط حاصل از اتصالات تأثیر نمی گذارد. درختان پیوستن معتبر:

اصل یک جدول یا نتیجه پرس و جو تعداد ردیف هایی است که در آن وجود دارد. فرض کنید جداول مربوطه دارای ویژگی های زیر هستند:

با در نظر گرفتن پیوندهای خود، کاردینالیته های زیر را دریافت می کنیم:

صرف نظر از ترتیبی که این سه جدول به هم متصل می شوند، همیشه همان ردیف های 2 متری به اتصال دوم منتقل می شوند.

اولین سفارش پیوستن، 2 میلیون ورودی movie_companies را تا 5 درصد شرکت‌هایی که ژاپنی هستند، فیلتر می‌کند. با فرض توزیع یکنواخت (ما بعدا در مورد اینکه چرا این را فرض می‌کنیم) بحث خواهیم کرد، این پیوند تقریبا 100 هزار ردیف را به همراه دارد. پیوستن به نتیجه با جدول عنوان فیلتر شده تنها 20 درصد از آن ردیف‌ها را از دهه 2000 حفظ می‌کند.

دومین سفارش پیوستن، 2 میلیون ورودی movie_companies را تا 20 درصد از عناوین ساخته شده در دهه 2000 فیلتر می کند. همین فرض یکنواختی وجود دارد، بنابراین اولین پیوند منجر به 400k ردیف می شود، به این معنی که ما 400k ردیف را به اتصال دوم منتقل می کنیم.

اگر دومین سفارش را انتخاب کرده باشیم، 4 برابر کار را انجام می دهیم.

تغییر فاکتور در حال حاضر در حالی که جابجایی تعداد ردیف های تولید شده را تغییر نمی دهد، باید اکنون در نظر گرفته شود زیرا بر عملکرد در مورد الگوریتم اتصال استفاده شده تأثیر می گذارد. 4 جهت اتصال خارجی/داخلی مختلف وجود دارد که منجر به 8 ترکیب ممکن می شود:

( c n ⋈ m c ) ⋈ t (cn \ پاپیون mc) \ پاپیون t ( c n ⋈ m c ) ⋈ t t ⋈ ( c n ⋈ m c ) t \ پاپیون (cn \ پاپیون mc) t ⋈ ( c n) ⋈

( m c ⋈ c n ) ⋈ t ( mc \ پاپیون cn ) \ پاپیون t ( m c ⋈ c n ) ⋈ t t ⋈ ( m c ⋈ c n ) t \ پاپیون ( mc \ پاپیون cn ) t ⋈ ( m c ⋈

( t ⋈ m c ) ⋈ c n (t \ پاپیون mc) \ پاپیون cn ( t ⋈ m c ) ⋈ c n c n ⋈ ( t ⋈ m c ) cn \ پاپیون (t \ پاپیون mc) c n ⋈ m ( c ⋈

( m c ⋈ t ) ⋈ c n ( mc \ پاپیون t ) \ پاپیون cn ( m c ⋈ t ) ⋈ c n c n ⋈ ( m c ⋈ t ) cn \ پاپیون ( mc \ پاپیون t ) c n ⋈ ( m c )

در نهایت، هر جدول را می توان به روش های مختلف اسکن کرد. فقط چهار نوع اسکن را در نظر بگیرید:

2 درختان را بپیوندید: کدام جفت جدول ابتدا به هم می پیوندد. × 2 2 جهت: هر یک از 2 اتصال می تواند ورودی خارجی و داخلی را با هم عوض کند. × 3 2 الگوریتم: هر یک از 2 پیوند حلقه هش، ادغام یا تودرتو را انتخاب می کند. × 4 3 اسکن: هر یک از 3 جدول به صورت متوالی یا از طریق اسکن نمایه، فقط فهرست یا بیت مپ خوانده می شود. = 4، 608

4608 روش مختلف برای اجرای این پرس و جو وجود دارد که در واقع یک مقدار کم است. پلان ها می توانند به صورت موازی اجرا شوند، تجمیع ها را می توان هش یا مرتب کرد، و غیره. همچنین شایان ذکر است که Postgres همه این طرح ها را ارزیابی نمی کند. از برنامه نویسی پویا (و یک الگوریتم ژنتیک برای پرس و جوهایی که شامل بیش از 12 اتصال است) برای هرس فضای جستجو استفاده می کند. !

بدتر از همه، هر عضویت به طور ترکیبی فضای جستجو را منفجر می کند:

1 به درختان بپیوندید: با دو جدول فقط یک راه برای پیوستن به آنها وجود دارد. × 2 1 جهت: 1 پیوستن به این معنی است که فقط 2 جهت وجود دارد. × 3 1 الگوریتم: الگوریتم اتصال می تواند یک اتصال هش، پیوند ادغام یا حلقه تو در تو باشد. × 4 2 اسکن: هر یک از 2 جدول به صورت متوالی یا از طریق اسکن نمایه، فقط فهرست یا بیت مپ خوانده می شود. = 96

2 به درخت ها بپیوندید: روش هایی که می توان 3 جدول را قبل از هر گونه تعویض ورودی ها به هم وصل کرد. × 2 2 جهت: هر یک از 2 اتصال می تواند ورودی خارجی و داخلی را با هم عوض کند. × 3 2 الگوریتم: هر یک از 2 پیوند حلقه هش، ادغام یا تودرتو را انتخاب می کند. × 4 3 اسکن: هر یک از 3 جدول به صورت متوالی یا از طریق اسکن نمایه، فقط فهرست یا بیت مپ خوانده می شود. = 4، 608

8 درخت‌ها را به هم بپیوندید: روش‌هایی که می‌توان 4 جدول را قبل از تعویض ورودی‌ها به یکدیگر متصل کرد. × 2 3 جهت: هر یک از 3 اتصال می تواند ورودی خارجی و داخلی را با هم عوض کند. × 3 3 الگوریتم: هر یک از 3 اتصال حلقه هش، ادغام یا تودرتو را انتخاب می کند. × 4 4 اسکن: هر یک از 4 جدول به صورت متوالی یا از طریق اسکن نمایه، فقط فهرست یا بیت مپ خوانده می شود. = 442، 368

25 درختان را بپیوندید: روش هایی که می توان 5 جدول را قبل از هر گونه تعویض ورودی ها به یکدیگر متصل کرد. × 2 4 جهت: هر یک از 4 اتصال می توانند ورودی خارجی و کدام داخلی را با هم عوض کنند. × 3 4 الگوریتم: هر یک از 4 اتصال حلقه هش، ادغام یا تودرتو را انتخاب می کند. × 4 5 اسکن: هر یک از 5 جدول به صورت متوالی یا از طریق اسکن نمایه، فقط فهرست یا بیت مپ خوانده می شود. = 33، 177، 600

56 درخت‌ها را بپیوندید: روش‌هایی که می‌توان 6 جدول را قبل از هر گونه تعویض ورودی‌ها به یکدیگر متصل کرد. × 2 5 جهت: هر یک از 5 اتصال می توانند ورودی خارجی و کدام داخلی را با هم عوض کنند. × 3 5 الگوریتم: هر یک از 5 اتصال حلقه هش، ادغام یا تودرتو را انتخاب می کند. × 4 6 اسکن: هر یک از 6 جدول به صورت متوالی یا از طریق اسکن نمایه، فقط فهرست یا بیت مپ خوانده می شود. = 1، 783، 627، 776

696 درخت‌ها را بپیوندید: روش‌هایی که می‌توان 7 جدول را قبل از تعویض ورودی‌ها به هم متصل کرد. × 2 6 جهت: هر یک از 6 اتصال می توانند ورودی خارجی و کدام داخلی را با هم عوض کنند. × 3 6 الگوریتم: هر یک از 6 اتصال حلقه هش، ادغام یا تودرتو را انتخاب می کند. × 4 7 اسکن: هر یک از 7 جدول به صورت متوالی یا از طریق اسکن نمایه، فقط فهرست یا بیت مپ خوانده می شود. = 532، 030، 685، 184

4، 698 درختان را بپیوندید: روش هایی که می توان 8 جدول را قبل از هر گونه تعویض ورودی ها به یکدیگر متصل کرد. × 2 7 جهت: هر یک از 7 اتصال می توانند ورودی خارجی و کدام داخلی را با هم عوض کنند. × 3 7 الگوریتم: هر یک از 7 اتصال حلقه هش، ادغام یا تودرتو را انتخاب می کند. × 4 8 اسکن: هر یک از 8 جدول به صورت متوالی یا از طریق اسکن نمایه، فقط فهرست یا بیت مپ خوانده می شود. = 86، 188، 970، 999، 808

20، 340 درختان را بپیوندید: روش هایی که می توان 9 جدول را قبل از هر گونه مبادله ورودی ها به یکدیگر متصل کرد. × 2 8 جهت: هر یک از 8 اتصال می توانند ورودی خارجی و کدام داخلی را با هم عوض کنند. × 3 8 الگوریتم: هر یک از 8 اتصال حلقه هش، ادغام یا تودرتو را انتخاب می کند. × 4 9 اسکن: هر یک از 9 جدول یا به صورت متوالی خوانده می شود یا از طریق اسکن نمایه، فقط فهرست یا بیت مپ خوانده می شود. = 8 , 955 , 727 , 561 , 359 , 360

242 , 160 درختان را بپیوندید: روش هایی که می توان 10 جدول را قبل از هر گونه تعویض ورودی ها به هم متصل کرد. × 2 9 جهت: هر یک از 9 اتصال می تواند ورودی خارجی و داخلی را با هم عوض کند. × 3 9 الگوریتم: هر یک از 9 اتصال حلقه هش، ادغام یا تودرتو را انتخاب می کند. × 4 10 اسکن: هر یک از 10 جدول به صورت متوالی یا از طریق اسکن نمایه، فقط فهرست یا بیت مپ خوانده می شود. = 2 , 558 , 960 , 455 , 762 , 575 , 360

1 , 490 , 850 درختان را بپیوندید: روش هایی که می توان 11 جدول را قبل از هر گونه تعویض ورودی ها به یکدیگر متصل کرد. × 2 10 جهت: هر یک از 10 اتصال می تواند ورودی خارجی و داخلی را با هم عوض کند. × 3 10 الگوریتم: هر یک از 10 پیوند حلقه هش، ادغام یا تودرتو را انتخاب می کند. × 4 11 اسکن: هر یک از 11 جدول به صورت متوالی یا از طریق اسکن نمایه، فقط فهرست یا بیت مپ خوانده می شود. = 378 , 099 , 722 , 048 , 923 , 238 , 400

11 , 932 , 560 به درختان بپیوندید: روش هایی که می توان 12 جدول را قبل از هر گونه تعویض ورودی ها به یکدیگر متصل کرد. × 2 11 جهت: هر یک از 11 اتصال می تواند ورودی خارجی و کدام داخلی را با هم عوض کند. × 3 11 الگوریتم: هر یک از 11 پیوند حلقه هش، ادغام یا تودرتو را انتخاب می کند. × 4 12 اسکن: هر یک از 12 جدول به صورت متوالی یا از طریق اسکن نمایه، فقط فهرست یا بیت مپ خوانده می شود. = 72 , 630 , 206 , 166 , 931 , 876 , 085 , 760 لات!

Postgres در اینجا در یک نقطه دشوار است. منطقی است که فکر کنیم به سادگی می‌تواند کاردینالیته‌ها را شمارش کند و طرحی را انتخاب کند که تعداد ردیف‌هایی را که به پیوندهای متوالی منتقل می‌شوند به حداقل می‌رساند.

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

در عوض، Postgres از آمار برای تخمین کاردینالیته ها استفاده می کند. برنامه ریز جدول pg_statistic را پرس و جو می کند و مقادیر مشترک را برای هر ستون و فرکانس آنها و برای بقیه یک هیستوگرام برمی گرداند. وقتی به پیوستن ها می روید، اوضاع کمی پیچیده تر می شود. Postgres نمی داند که ردیف های یک جدول چگونه بر دیگری توزیع شده اند. برای دور زدن این موضوع، فرض می شود که فراوانی یک مقدار داده شده در جدول اول را می توان به سادگی روی جدول دوم اعمال کرد. این فرض توزیع یکنواختی است که قبلا ذکر کردم.

با فرض اینکه یک توزیع یکنواخت به عنوان یک اکتشافی خوب است، اما زمانی که شکست می خورد، به سختی از کار می افتد. با نگاهی به گذشته به ترتیب پیوستن قبلی ( c n ′ ⋈ m c ) ≈ 100 k , سپس ⋈ t ≈ 20 k (cn' \bowtie mc) \approx 100\text{k}, \text{ سپس } \bowtie\ t'\nproext ج) ≈ 100 k و سپس ⋈ t ≈ 20 k، ما 2 میلیون ورودی movie_companies را با این فرض که 5٪ از آنها از شرکت های ژاپنی بودند فیلتر کردیم. اما اگر 5 درصد از شرکت های ژاپنی در واقع مسئول 50 درصد فیلم ها باشند، چه؟ اولین اتصال 1 متر ردیف ایجاد می کند!

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

یک تخمین بد در یک اتصال اولیه می‌تواند از طریق بقیه درخت اتصال آبشاری کند و همه تخمین‌های دیگر را خراب کند.

Postgres همیشه طرح را با کمترین هزینه انتخاب می‌کند، و ما نمی‌توانیم مدل هزینه آن را بدون تغییر کد منبع آن تغییر دهیم، بنابراین چگونه می‌توانیم آن را به سمت انتخاب طرح‌های مختلف که هزینه‌های بالاتری دارند هدایت کنیم؟

pg_hint_plan یک برنامه افزودنی شخص ثالث به زیبایی ساده است: فقط با افزودن "نکات" ساختار یافته به عنوان نظرات بالای عبارات SQL، می توانید Postgres را به سمت طرح هایی سوق دهید که از دستورالعمل های ارائه شده در راهنمایی استفاده می کنند. به عنوان مثال:

این راهنمایی استفاده از HashJoin را برای پیوستن به pgbench_accounts و pgbench_branches و انجام یک اسکن متوالی جدول pgbench_accounts الزامی می‌کند. طرح پرس و جو واقعی به خوبی از آن پیروی می کند.

با توجه به اینکه می‌توانیم Postgres را تحت تأثیر قرار دهیم تا با استفاده از راهنمایی‌های pg_hint_plan، طرح‌های پرس و جوی متفاوت و بالقوه بهتر را انتخاب کند، سؤالی که با آن شروع می‌کنیم این است:

آیا یک مدل زبان می تواند یاد بگیرد که نکاتی را تولید کند که منجر به طرح های پرس و جو بهتر شود؟

چه چیزی ممکن است این مشکل را به یک مشکل ارزشمند تبدیل کند؟

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

ایده دوم - و آنچه من معتقدم فرمول بندی صحیح است - در یک الگوی استفاده از پایگاه داده خاص نهفته است: بارهای سنگین تحلیلی. اگر پرس‌و‌جوها هزاران بار با استفاده از طرح‌های پیش‌فرض Postgres زیر بهینه اجرا می‌شوند، افزایش کارایی روی میز باقی می‌ماند. در عوض، یک مدل می تواند آموزش داده شود تا راه بهتری برای اجرای یک پرس و جو خاص پیدا کند. فرآیند آموزش ممکن است نیاز به اجرای آن پرس و جو ده ها تا صدها بار از قبل داشته باشد، اما هزینه مستهلک شده در تمام اجراهای پرس و جو به شدت کمتر خواهد بود.

هدف این نیست که برای پرس و جوهای یکباره، Postgres را در مرز پارتو با کارایی/زمان شکست دهیم، اما ممکن است بتوانیم آن را در پرس و جوهایی که بارها و بارها انجام می دهند، شکست دهیم.

من تصمیم گرفتم با یک مدل کوچک 4B شروع کنم زیرا آموزش/استنباط خودم در مورد دکل 2x RTX 3090 (با نام محبت آمیز FLOpper) که در خانه دارم، راحت‌تر است.

تقریبا زمانی که من این پروژه را شروع کردم، خانواده مدل های Qwen 3.8 منتشر شد، متاسفانه بدون نسخه 4B. با این حال، من با یک تقطیر Qwen 3.8 4B از یک آزمایشگاه کوچک در آلمان به نام Empero برخورد کردم و کنجکاو شدم. آنها از مدل 2.4T Qwen 3.8 به عنوان یک مدل معلم برای تقطیر آموخته ها به Qwen 3.5 4B استفاده کردند و empero-ai/Qwen3.8-4B-Distill را تولید کردند. این مدل مقطر کاملا بهتر از مدل پایه 3.5 خود نیست. در وظایف MMLU بهتر و در وظایف GSM8K کمی بدتر عمل می کند.

به عبارت دیگر، این تقطیر زمانی که بر اساس وسعت دانش عمومی ارزیابی شود، عملکرد بهتری دارد و در استدلال ریاضی چند مرحله ای کمی بدتر است. اینکه کدام برای وظیفه ما بهتر است، نمی دانم. تصمیم گرفتم در هر صورت از مدل تقطیر شده استفاده کنم.

در حالی که مدل قفل شده بود، یک مهار کننده سبک وزن، qo-agent ساختم که تولید نکات را هماهنگ می کرد. شش ابزار زیر به آن داده شد:

برای استفاده از خروجی های ساخت یافته، به عامل دستور داده شد که اشیاء JSON PlanAction را تولید کند. فراخوانی به ارزیابی_candidate سپس اشیاء PlanAction را به صورت نکات کامپایل کرد و آنها را به پرس و جو اصلی اضافه کرد.

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

لیس و همکاران معیار Join Order Benchmark (JOB) را در بهینه سازهای پرس و جو واقعا چقدر خوب هستند معرفی کرد؟ . آنها از آن برای ارزیابی تخمین کاردینالیته و بهینه‌سازی سفارش با استفاده از مجموعه داده آشنای IMDb ما استفاده کردند.

این شامل 113 پرس و جو است که در 33 قالب پرس و جو پخش شده است. قالب های پرس و جو از طریق اسکلت رابطه ای خود متفاوت هستند. آنها به جداول مختلف ارجاع می دهند و آنها را با محمولات پیوستن مختلف به هم وصل می کنند. شما می توانید در مورد آنها به عنوان یک خانواده ساختاری از سؤالات فکر کنید که می توان به آنها پاسخ داد. پرس و جوهای مشتق شده از الگوها جداول استفاده شده و توپولوژی نمودار پیوست را حفظ می کنند اما محمول های انتخاب را تغییر می دهند.

الگوی پرس و جو 2 - "اولین عنوان فیلمی که به ترتیب حروف الفبا با شرکتی از کشور X مرتبط است و با کلمه کلیدی character-name-in-title برچسب گذاری شده است چیست؟"

... و در اینجا دو پرس و جو واقعی از JOB از این الگو مشتق شده است:

پرس و جو 2a - "اولین عنوان فیلم از نظر حروف الفبا مرتبط با یک شرکت آلمانی چیست؟"

Query 2d - "اولین عنوان فیلم از نظر حروف الفبا مرتبط با یک شرکت آمریکایی چیست؟"

معیار مرتبط دیگر معیار تخمین کاردینالیته (CEB) است که در Flow-loss: Learning Cardinality Estimates That Matter معرفی شده است. از همان پایگاه داده IMDb استفاده می‌کند و معیار بسیار بزرگ‌تری است که شامل 13.6 هزار پرس‌و‌جوی مصنوعی است که در 16 قالب جستجو سازمان‌دهی شده‌اند. تعریف CEB از یک الگو نسبت به JOB ضعیف‌تر است. دو الگوی CEB می‌توانند نمودار پیوستن یکسانی را به اشتراک بگذارند و فقط در محمولات انتخابی متفاوت هستند. در JOB، نمودار پیوستن هر قالب منحصر به فرد است. .

با توجه به اندازه آن، CEB برای آموزش مدل مناسب بود. از JOB برای اعتبارسنجی عملکرد مدل استفاده می شود.

شاید تعجب کنید که آیا آموزش و آزمایش در IMDb منطقی است؟ اگر خوب کار کند، آیا مدل این پایگاه داده خاص را به خوبی یاد نگرفته است؟

من استدلال می کنم که این دقیقا نکته است. ما می خواهیم مدل ما IMDb را به خوبی یاد بگیرد. با توجه به فرمول مشکل ما، اگر این عامل به طور مداوم برای بارهای کاری تحلیلی یک شرکت در پایگاه های داده خاص خود استفاده می شود، نیازی نیست به همه پایگاه های داده تعمیم دهیم.

مسئله واقعی این است که اطمینان حاصل کنیم که در طول آموزش در CEB به الگوهای پرس و جوی JOB بیش از حد تناسب نداریم. این مدل باید IMDb را به گونه ای یاد بگیرد که با توجه به هر پرس و جو، حتی برای خانواده های پرس و جوی ساختاری که قبلا دیده نشده است، همچنان قادر به تولید یک طرح خوب باشد. در عمل، این بدان معناست که ما باید پرس و جوهای CEB را که شکلی مشابه هر یک از جستارهای JOB دارند، هرس کنیم.

بیایید «توپولوژی» یک پرس و جو را به عنوان نمودار پیوست ساختاری آن تعریف کنیم (نام جداول غیر مستعار به عنوان گره و پیوندها به عنوان یال). نمودار پیوستن تمام محمولات گزینش پذیری را حذف می کند. ما فقط علاقه مند به پیوستن در اینجا هستیم.

پرس و جوهای CEB که یک توپولوژی را با یک جستار JOB به اشتراک می گذارند از مجموعه آموزشی حذف می شوند. من یک اسکریپت کوچک نوشتم تا تمام جستارهای JOB و CEB را به توپولوژی آنها تبدیل کنم و بررسی کردم که آیا همپوشانی وجود دارد یا خیر. وجود نداشت، بنابراین نیازی به فیلتر نبود.

شغل: 113 پرس و جو، 33 قالب، 33 توپولوژی

CEB: 13646 پرس و جو، 16 قالب، 12 توپولوژی

الگوهای JOB و CEB به عنوان نماد توپولوژی آنها نمایش داده می شوند.

قبل از اینکه به بنچمارک کردن نماینده و انجام دوره های آموزشی بپردازیم، باید در مورد نحوه اجرای واقعی Postgres صحبت کنیم، زیرا مستقیما بر روند آموزش تأثیر می گذارد.

اگر دقیقا همان کوئری را در Postgres 20 بار متوالی اجرا کنیم، هر بار اجرا به همان اندازه زمان نمی برد. در کارهای روزمره، این موضوع مهمی نیست. اما کل پایان نامه، و خود فرآیند آموزش، به اندازه گیری اینکه آیا یکی از راه های اجرای یک پرس و جو سریعتر از پیش فرض Postgres است، متکی است. این بدان معناست که ما باید هر کاری که در توان داریم انجام دهیم تا Postgres را از نویز خارج کنیم.

ابتدا باید بفهمم اجرای کوئری های Postgres چقدر پر سر و صدا هستند.

من با ایجاد قابلیت "کالیبراسیون" در جریان کار آزمایشی خود شروع کردم. فرآیند کالیبراسیون ساده بود: کانتینرهای N N N Docker ساخته شده از یک تصویر Postgres را اجرا کنید، به هر کدام یک تکه ثابت از هسته های CPU و RAM برای استفاده داده می شود. من N = 4 N = 4 N = 4 را برای شروع تنظیم کردم. هر چیزی کمتر ممکن است آموزش آینده را بسیار کند کند و هر چیزی بالاتر ممکن است منجر به اختلاف بیشتر CPU شود که به معنای نویز بیشتر است. به هر کانتینر 4 هسته برای استفاده داده شد و 8 گیگابایت حافظه در آن بسته شد.

هنگام راه‌اندازی، هر کانتینر Postgres را با تنظیمات یکسان مقداردهی کرد و داده‌های IMDb را بارگیری کرد. سپس کالیبراسیون یک Thread Pool با اندازه چهار را باز کرد و تمام 113 پرس و جو را در یک صف مشترک قرار داد. هر زمان که یک کانتینر اندازه گیری یک پرس و جو را به پایان می رساند، مورد بعدی را از صف خارج می کند.

فرآیند اندازه گیری واقعی دو مرحله داشت:

بنابراین گرم کردن یک پرس و جو به چه معناست؟ ما باید برخی از اصول سیستم عامل را بررسی کنیم تا بفهمیم.

هر زمان که Postgres یک پرس و جو را اجرا می کند، از سیستم عامل (در مورد ما، لینوکس) صفحاتی از داده ها را می خواهد. لینوکس ابتدا حافظه نهان فایل سیستم خود یعنی کش صفحه را بررسی می کند. اگر صفحات موجود باشند، لینوکس آنها را ارسال می کند. در غیر این صورت آنها را از روی دیسک می خواند، آنها را در حافظه پنهان خود ذخیره می کند و سپس آنها را ارسال می کند. Postgres به نوبه خود صفحات دریافتی را در حافظه پنهان shared_buffers خود برای استفاده مجدد آسان نگه می دارد. وقتی shared_buffers شروع به سرریز شدن می کند، Postgres صفحات را بیرون می کند. اگر دوباره به آن صفحات نیاز داشت، باید یک بار دیگر از لینوکس بپرسد.

هر بار که یک ضربه کش در shared_buffers برای یک صفحه وجود دارد، Postgres شمارنده‌ای به نام بلوک‌های ضربه مشترک (SHBs) را افزایش می‌دهد. اگر مجبور باشد از لینوکس بپرسد، «بلوک‌های خواندن مشترک» (SRB) را افزایش می‌دهد.

خواندن متن کامل در هکرنیوزبه زبان اصلی، در سایت ناشر باز می‌شود
متن اصلی (انگلیسی)

Training a 4B model to produce 81% faster query plans than Postgres

Article URL: https://rohanbansal.com/qorl Comments URL: https://news.ycombinator.com/item?id=49731285 Points: 297 # Comments: 54

همه‌ی اخبار فناوری