SQLite یا PostgreSQL؛ یک نویسنده سریع است، ۱۶ نویسنده برنده را عوض می‌کنند

|نویسنده: تیم تحریریه QUASA|7 دقیقه مطالعه| 1
SQLite یا PostgreSQL؛ یک نویسنده سریع است، ۱۶ نویسنده برنده را عوض می‌کنند

اگر داده روی همان ماشینِ برنامه می‌ماند و نوشتن‌ها می‌توانند نوبتی انجام شوند، SQLite انتخاب ساده‌ای است؛ برای دادهٔ مشترک میان چند سرور یا نوشتن‌های هم‌زمانِ پرفشار، PostgreSQL مناسب‌تر است. در بنچمارک درج روی یک دستگاه، SQLite با یک اتصال ۲۳٬۴۰۳ درج در ثانیه و PostgreSQL با یک اتصال ۷٬۷۴۰ درج در ثانیه ثبت کردند، اما PostgreSQL در آزمون جداگانهٔ درج با ۱۶ اتصال به ۳۵٬۳۷۰ درج در ثانیه رسید.

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

داده کجاست و چند سرور به آن می‌نویسند؟

راهنمای رسمی SQLite دادهٔ محلیِ برنامه، ابزارهای رومیزی و بسیاری از وب‌سایت‌های کم‌تا‌میان‌ترافیک را از کاربردهای مناسب می‌داند. در این معماری، موتور SQLite همراه برنامه اجرا می‌شود و داده در فایل قرار دارد؛ راه‌اندازی و نگهداری یک سرویس پایگاه دادهٔ مستقل لازم نیست. برای سرویس تک‌سروری که همان ماشین محل اجرای برنامه و نگهداری فایل است، این سادگی می‌تواند مزیت عملی بزرگی باشد.

اما محل حضور کاربر با محل اجرای دستور SQL یکی نیست. ممکن است کاربران از سراسر شبکه به یک سرور برنامه درخواست بفرستند، در حالی که آن سرور به فایل محلی SQLite دسترسی دارد. مسئله وقتی عوض می‌شود که خودِ چند سرور برنامه بخواهند به یک وضعیت مشترک و قابل‌نوشتن دسترسی داشته باشند. در آن حالت، PostgreSQL به‌عنوان سرویس پایگاه داده می‌تواند نقطهٔ مشترک اتصال آن‌ها باشد؛ اشتراک مستقیم فایل SQLite از راه فایل‌سیستم شبکه، به‌ویژه با قفل‌گذاری نامطمئن یا تأخیر شبکه، همان کارکرد را با همان اطمینان فراهم نمی‌کند.

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

WAL خواندن را آزادتر می‌کند، صف نویسندگان را حذف نمی‌کند

مستندات WAL در SQLite توضیح می‌دهد که خواننده و نویسنده می‌توانند هم‌زمان کار کنند، ولی برای هر فایلِ پایگاه داده در هر لحظه فقط یک نویسنده فعال است. خواننده نسخه‌ای سازگار از داده را می‌بیند و نویسنده تغییرات را به فایل WAL می‌افزاید؛ از این راه، خواندن معمولاً پشت نوشتن نمی‌ماند. این سازوکار برای سرویس‌هایی با خواندن فراوان مفید است، اما چند تراکنش نوشتن روی همان فایل همچنان باید برای نوبت خود منتظر بمانند.

نوبتی‌شدن نوشتن لزوماً گلوگاه نیست. وقتی تراکنش‌ها کوتاه‌اند و نرخ ورود آن‌ها از توان پردازشِ نویسنده جلو نمی‌زند، صف می‌تواند کوچک بماند. طولانی‌شدن تراکنش، جهش هم‌زمان درخواست‌ها یا کاری که تا پایان تراکنش قفل نوشتن را نگه می‌دارد، زمان انتظار بقیه را افزایش می‌دهد. از این رو، نسبت خواندن به نوشتن به‌تنهایی کافی نیست: مدت اشغال مسیر نوشتن هم باید شناخته شود.

مستندات هم‌زمانی PostgreSQL سازوکار MVCC را شرح می‌دهد: خواندن معمولی با قفلِ نوشتن تداخل ندارد و چند نشست می‌توانند هم‌زمان با پایگاه داده کار کنند. این ویژگی به معنای بی‌هزینه‌شدن همهٔ نوشتن‌ها نیست؛ تغییر هم‌زمان همان ردیف می‌تواند به انتظار یا برخورد تراکنش‌ها بینجامد و دیسک و پردازنده هم ظرفیت محدود دارند. مزیت مرتبط با این انتخاب، امکان پیش‌بردن نوشتن‌های مستقل از چند اتصال است، نه وعدهٔ رشد نامحدود با افزودن اتصال.

بنچمارک چه شرایطی را کنار هم گذاشت؟

نتایج منتشرشده روی Apple M2 Pro، با هر دو پایگاه داده روی یک SSD و با طرح جدول یکسان به دست آمده‌اند. SQLite از فایل واقعی در حالت WAL و درایور داخلی Bun استفاده کرده است؛ PostgreSQL به‌صورت بومی، بدون کانتینر، با درایور جداگانه اجرا شده است. پس نتیجه، کارایی ترکیب موتور، درایور، تنظیمات و سخت‌افزار را نشان می‌دهد. این نکته به‌ویژه در مقایسهٔ تک‌اتصالی مهم است، چون تماس درون فرایند برنامه با SQLite و ارتباط با فرایند PostgreSQL هزینهٔ یکسانی ندارند.

  • درج ترتیبی: هر فراخوانی یک ردیف درج می‌کند و چند درج در یک عملیات تجمیع نمی‌شوند. برتری SQLite در این سناریو، پاسخ به همین الگوی ساده و تک‌اتصالی است.
  • بار ترکیبی: خواندن با کلید اصلی در کنار درج اجرا می‌شود. SQLite در نتیجهٔ منتشرشده برای این بار خواندن‌محور نیز جلوست، اما نسبت کارها، نوع پرس‌وجو و شاخص‌های همان طرح جدول بر نتیجه اثر دارند.
  • درج هم‌زمان: اتصال‌های متعدد PostgreSQL به‌طور موازی درج می‌کنند. نویسندگان SQLite می‌توانند درخواست بفرستند، ولی روی یک فایل هم‌زمان فعال نمی‌شوند؛ نبودِ آزمون معادل برای SQLite مانع از آن است که دو عدد را نتیجهٔ رقابتِ هم‌شرط بخوانیم.

حتی دو مقدار تک‌اتصالی PostgreSQL در بخش‌های ترتیبی و مقیاس‌پذیری مخزن یکسان نیستند، چون از دو سناریوی جداگانه آمده‌اند. برای فهمیدن اثر افزایش اتصال باید روند بخش مقیاس‌پذیری را درون همان بخش دنبال کرد. از طرف دیگر، عبور بازده چنداتصالی PostgreSQL از نتیجهٔ تک‌اتصالی SQLite نشان می‌دهد که رتبهٔ کارایی، مستقل از الگوی هم‌زمانی نیست.

چرا همان عدد روی سخت‌افزار دیگر تکرار نمی‌شود؟

هر دو موتور در این آزمون روی یک ماشین و دیسک یکسان‌اند؛ بنابراین رفت‌وبرگشت به پایگاه دادهٔ دوردست در نتیجه نیامده است. در استقرار چندسروری، PostgreSQL ممکن است از راه شبکه فراخوانده شود و زمان پاسخ هر درخواست تغییر کند. نوع SSD، حافظه، سیستم‌عامل، درایور، اندازهٔ ردیف و شاخص‌ها نیز می‌توانند سهم هر هزینه را جابه‌جا کنند. به همین دلیل، نتیجهٔ درج یک ردیف را نمی‌توان به جست‌وجوی پیچیده، به‌روزرسانی چند جدول یا تراکنشی با منطق تجاری طولانی تعمیم داد.

تفاوت دیگری در سیاست دوام داده وجود دارد: SQLite در این آزمون با synchronous=NORMAL و PostgreSQL با synchronous_commit=on تنظیم شده‌اند. در حالت WAL، تنظیم NORMAL در SQLite می‌تواند اجازه دهد تراکنش تأییدشده پس از قطع برق یا بازنشانی سخت‌افزاری برگردد؛ این نکته با خراب‌شدن فایل پایگاه داده یکی نیست. اگر محصول به تأیید پایدار هر تراکنش نیاز دارد، مقایسهٔ سرعت باید پس از هماهنگ‌کردن انتظار دوام داده انجام شود. انتخاب یک تنظیم سریع‌تر، به‌تنهایی دلیل برتری عمومی موتور نیست.

خودِ روش درج هم نتیجه را محدود می‌کند. درج تک‌ردیفی، سربار هر فراخوانی و هر تأیید را برجسته می‌کند؛ تجمیع چند تغییر در یک تراکنش می‌تواند نسبت هزینه‌ها را تغییر دهد. برای بار واقعی، زمان پاسخ در دورهٔ شلوغی و انتظار نوشتن از میانگین عملیات در ثانیه گویاترند. اگر برنامه بیشتر می‌خواند، کارهای طولانی خواندن و رفتار WAL هنگام بازگرداندن تغییرات به فایل اصلی نیز می‌توانند اهمیت پیدا کنند.

درخت تصمیم برای انتخاب پروژه

اگر داده متعلق به یک برنامه روی همان ماشین است، فایل محلی مناسبِ استقرار است و نوشتن‌ها می‌توانند سریع نوبت بگیرند، SQLite انتخابی متناسب با معماری است. این حالت می‌تواند سرویس وب تک‌سروری را هم شامل شود؛ داشتن کاربران شبکه‌ای به معنی دسترسی مستقیم آن‌ها به فایل نیست. رشد تعداد کاربران تا زمانی که صف نوشتن و نیاز به سرورهای بیشتر مسئله نشده، به‌خودی‌خود الزام فنی برای مهاجرت نمی‌سازد.

اگر چند سرور باید روی یک مجموعه‌دادهٔ قابل‌نوشتن کار کنند، یا در اوج بار، تراکنش‌های مستقل پشت نویسندهٔ واحد می‌مانند و زمان پاسخِ موردنیاز محصول را از دست می‌دهند، PostgreSQL انتخاب روشن‌تری است. مرز تصمیم، شمار رکوردها یا یک عدد ثابت از بنچمارک نیست؛ ترکیب محل داده، هم‌زمانی واقعی و سطح دوام موردنیاز است. نرخ ورود نوشتن، مدت تراکنش و تأخیر درخواست‌ها نشان می‌دهند که نوبت‌گرفتن هنوز پذیرفتنی است یا به هزینه‌ای برای معماری تبدیل شده است.

بیشتر بخوانید:

اشتراک‌گذاری:

عضویت در خبرنامه

تازه‌ترین اخبار Web3، هوش مصنوعی و رمزارز را مستقیم در صندوق ایمیل خود دریافت کنید.

0