SQLite: پایگاه داده‌ای که ابر انتظارش را نداشت — و همچنان در حال پیروزی است

اشتراک‌گذاری:
SQLite: پایگاه داده‌ای که ابر انتظارش را نداشت — و همچنان در حال پیروزی است

تقریباً یک تریلیون نصب فعال از SQLite در جهان وجود دارد. این عدد که از مستندات خود پروژه SQLite گرفته شده، تخمین بازاریابی نیست — یک واقعیت معماری است. هر iPhone با SQLite عرضه می‌شود. هر دستگاه Android آن را اجرا می‌کند. Firefox از آن برای ذخیره تاریخچه، بوکمارک‌ها و کوکی‌ها استفاده می‌کند. Chrome از آن به عنوان backend پایگاه داده خود بهره می‌برد. Skype، Dropbox، iTunes، VLC و کل Adobe Creative Suite آن را جاسازی کرده‌اند. کتابخانه کنگره ایالات متحده آن را به عنوان یک فرمت بایگانی توصیه می‌کند. SQLite بر اساس تعداد نصب‌ها، پرکاربردترین موتور پایگاه داده موجود است — و تا همین اواخر، اکثر توسعه‌دهندگان آن را چیزی می‌دانستند که در داخل اپلیکیشن‌های موبایل عرضه می‌شود، نه یک زیرساخت جدی.

این چارچوب فکری اکنون منسوخ شده است. در سال ۲۰۲۶، SQLite در داخل شبکه لبه جهانی Cloudflare اجرا می‌شود، از طریق فورک libSQL تورسو (Turso) اپلیکیشن‌های توزیع‌شده را توانمند می‌سازد، و پایه‌گذار معماری اپلیکیشن local-first است که توجه جدی مهندسی را به خود جلب کرده است. پایگاه داده‌ای که سی سال «مناسب برای تولید نیست» خوانده می‌شد، اکنون به آرامی تعریف تولید را بازتعریف می‌کند.

SQLite واقعاً چیست

SQLite یک کتابخانه C است — حدود ۱۵۵,۰۰۰ خط — که یک موتور پایگاه داده کامل SQL را در یک فایل واحد و بدون هیچ وابستگی خارجی، فرآیند سرور و بدون پیکربندی پیاده‌سازی می‌کند. یک پایگاه داده فقط یک فایل روی دیسک است. باز کردن آن نیازی به رشته اتصال، دست‌افشانی احراز هویت یا دیمون در حال اجرا برای اتصال ندارد. کتابخانه را لینک می‌کنید، فایل را باز می‌کنید و SQL اجرا می‌کنید. این تمام راه‌اندازی است.

با وجود سادگی، SQLite کاملاً سازگار با ACID است. نوشتن‌ها اتمی هستند. خواندن‌های همزمان از طریق حالت WAL (Write-Ahead Log) پشتیبانی می‌شوند. فرمت روی دیسک از سال ۲۰۰۴ پایدار و کاملاً سازگار با عقب است. از SQL-92 کامل با بیشتر SQL:1999، از جمله window functions، CTEs و عملگرهای JSON اضافه شده در نسخه‌های جدیدتر پشتیبانی می‌کند. این پروژه توسط یک تیم کوچک تحت وقف دامنه عمومی نگهداری می‌شود — بدون مجوز، بدون حق نشر، بدون توافقنامه مشارکت.

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

SQLite در لبه: Cloudflare D1، Turso و LiteFS

Cloudflare D1 که در سال ۲۰۲۳ به صورت عمومی عرضه شد و در طول ۲۰۲۴–۲۰۲۵ به طور قابل توجهی گسترش یافت، SQLite است که در داخل Cloudflare Workers در بیش از ۳۰۰ مکان لبه در سراسر جهان اجرا می‌شود. هنگامی که یک Worker یک کوئری D1 را اجرا می‌کند، در برابر یک فایل SQLite که در گره لبه نزدیک به کاربر قرار دارد، اجرا می‌شود. خواندن‌ها زیر میلی‌ثانیه هستند. پایگاه داده می‌تواند بدون تأمین منابع تا ۱۰ GB در هر پایگاه داده مقیاس شود — یک پایگاه داده D1 را با یک دستور CLI ایجاد می‌کنید و بلافاصله در سطح جهانی در دسترس است.

D1 مشکل نوشتن را از طریق یک مدل primary-replica حل می‌کند: نوشتن‌ها به یک مکان primary می‌روند و به صورت ناهمزمان به تمام گره‌های لبه تکرار می‌شوند. برای بارهای کاری سنگین خواندن — که بیشتر اپلیکیشن‌های وب را توصیف می‌کند — مزیت تأخیر نسبت به یک نمونه PostgreSQL تک منطقه قابل توجه است. Cloudflare گزارش می‌دهد که D1 تا اوایل سال ۲۰۲۶ بیش از ۵۰ میلیارد ردیف خوانده شده در ماه را در سراسر پایگاه مشتریان خود ارائه می‌دهد.

Turso که بر اساس libSQL ساخته شده — یک فورک منبع باز از SQLite که توسط ChiselStrike نگهداری می‌شود — رویکرد معماری متفاوتی دارد. libSQL SQLite را با تکرار بومی، حالت سرور و پشتیبانی API HTTP گسترش می‌دهد در حالی که با فایل‌های استاندارد SQLite سازگار با سیم باقی می‌ماند. Turso replicaهای جاسازی شده ارائه می‌دهد: اپلیکیشن شما یک replica محلی SQLite اجرا می‌کند که با یک پایگاه داده مرکزی همگام می‌ماند و به شما خوانش‌های محلی با تأخیر صفر و سازگاری نهایی در نوشتن می‌دهد. این مدل به طور صریح برای زمان‌های اجرای لبه و توابع serverless طراحی شده است که هزینه تأخیر فراخوانی پایگاه داده از راه دور بازدارنده است.

LiteFS که توسط بن جانسون توسعه یافته و اکنون تحت چتر Fly.io نگهداری می‌شود، یک رویکرد مبتنی بر FUSE برای تکرار SQLite دارد. نوشتن‌های سیستم فایل را در سطح OS رهگیری می‌کند و لاگ write-ahead SQLite را از طریق یک لایه اجماع به گره‌های دیگر تکرار می‌کند. اپلیکیشن‌ها نیاز به تغییر کد ندارند — LiteFS بین اپلیکیشن و سیستم فایل قرار می‌گیرد و پایگاه داده‌های SQLite را به صورت شفاف در یک کلاستر Fly.io همگام می‌کند. Fly.io Volumes، لایه ذخیره‌سازی پایدار برای اپ‌های Fly، همراه با LiteFS به توسعه‌دهندگان یک راه‌اندازی SQLite توزیع‌شده با failover خودکار و تکرار در چندین منطقه می‌دهد.

SQLite-over-HTTP و الگوهای دسترسی جدید

یکی از جالب‌ترین تحولات در اکوسیستم SQLite ظهور لایه‌های دسترسی مبتنی بر HTTP است که آن را بیشتر شبیه یک پایگاه داده سنتی client-server می‌کند بدون اینکه مزایای جاسازی شده خود را از دست بدهد. حالت سرور libSQL یک API WebSocket و HTTP ارائه می‌دهد که مشتریان می‌توانند از راه دور به آن متصل شوند — یعنی می‌توان از یک مرورگر، یک اپ موبایل یا یک تابع serverless با استفاده از معناشناسی استاندارد HTTP از یک پایگاه داده SQLite در حال اجرا بر روی یک سرور کوئری گرفت.

این مهم است زیرا SQLite را برای محیط‌هایی باز می‌کند که جاسازی مستقیم کتابخانه ممکن نیست. یک اپلیکیشن Next.js مستقر در Vercel نمی‌تواند یک کتابخانه بومی SQLite را باندل کند — اما می‌تواند درخواست‌های HTTP به یک پایگاه داده Turso ارسال کند و نتایج کوئری SQL را به صورت JSON دریافت کند. تجربه توسعه‌دهنده تقریباً مشابه کوئری زدن Postgres از طریق یک connection pool است، اما موتور زیرین SQLite است، با تمام سادگی عملیاتی که به همراه دارد.

Bun، زمان اجرای JavaScript که به عنوان جایگزین سریع‌تر Node.js در حال جذب است، با پشتیبانی بومی SQLite از طریق ماژول bun:sqlite عرضه می‌شود — بدون نیاز به npm install، بدون کامپایل ماژول بومی، بدون node-gyp. const db = new Database("mydb.sqlite"); تمام راه‌اندازی است. اعداد عملکردی که Bun برای پیاده‌سازی SQLite خود ذکر می‌کند — بیش از ۴ میلیون خواندن در ثانیه روی یک لپ‌تاپ — نشان می‌دهد که یک پایگاه داده بدون سربار شبکه چقدر می‌تواند سریع باشد وقتی در همان فرآیند کد اپلیکیشن شما اجرا می‌شود.

معماری local-first و ظهور CRDTها

جنبش local-first در توسعه اپلیکیشن‌های وب بر اساس یک ادعای خاص ساخته شده است: اینکه معماری درست برای اکثر اپلیکیشن‌ها معماری‌ای است که پایگاه داده روی مشتری زندگی می‌کند، خواندن‌ها به دلیل ضربه به ذخیره‌سازی محلی فوری هستند و همگام‌سازی با سرور در پس‌زمینه اتفاق می‌افتد. تجربه کاربر سریع‌تر است، قابلیت آفلاین به صورت داخلی وجود دارد و سرور به یک رله همگام‌سازی تبدیل می‌شود نه یک گلوگاه کوئری.

SQLite گزینه طبیعی برای این معماری است زیرا همه جا اجرا می‌شود — در مرورگر از طریق WebAssembly (wa-sqlite، sql.js)، در اپ‌های Electron به صورت بومی، در موبایل از طریق SQLite داخلی پلتفرم، و در گره‌های لبه از طریق D1 یا Turso. همان کوئری‌های SQL در تمام این محیط‌ها در برابر فایل‌هایی که اساساً با یکدیگر سازگار هستند کار می‌کنند.

مشکل سخت در معماری local-first حل تعارض است: اگر دو مشتری هر دو در حالت آفلاین به یک replica محلی SQLite بنویسند، چگونه آن نوشته‌ها را هنگام اتصال مجدد ادغام می‌کنید؟ اینجاست که CRDTها (Conflict-free Replicated Data Types) وارد تصویر می‌شوند. cr-sqlite، یک افزونه SQLite که توسط مت وونلاو در Vlcn.io توسعه یافته، معناشناسی CRDT را مستقیماً در SQLite با ابزاری کردن جداول استاندارد SQL با یک ساعت Lamport و یک تابع ادغام پیاده‌سازی می‌کند. دو پایگاه داده cr-sqlite می‌توانند بدون یک مرجع مرکزی به صورت قطعی ادغام شوند. هرگونه تعارض در سطح سطر توسط قوانین ادغام CRDT حل می‌شود، نه توسط یک سرور که تصمیم می‌گیرد کدام نوشتن برنده است.

این ترکیب — SQLite برای ذخیره‌سازی، CRDTها برای معناشناسی ادغام، یک رله همگام‌سازی برای اتصال — معماری پشت ابزارهایی مانند ElectricSQL، Replicache و Zero (از تیم Rocicorp که Replicache را ساخته) است. دیگر کاملاً تجربی نیست: Linear، ابزار مدیریت پروژه، از معماری مبتنی بر SQLite local-first برای اپ دسکتاپ خود استفاده می‌کند و حس سریع خود را به طور خاص به این واقعیت نسبت می‌دهد که هر تعامل به یک پایگاه داده محلی برخورد می‌کند نه یک API از راه دور.

ابزارهای توسعه‌دهنده در سال ۲۰۲۶

اکوسیستم ORM و ابزارها با نقش گسترده‌تر SQLite هماهنگ شده است. Drizzle ORM، یکی از سریع‌ترین رشدها در ORMهای TypeScript، SQLite را به عنوان یک هدف درجه یک در کنار PostgreSQL و MySQL در نظر می‌گیرد — با آداپتورهای خاص برای better-sqlite3، SQLite بومی Bun، libSQL، D1 و Turso. استنتاج نوع Drizzle به این معنی است که شمای SQLite شما تایپ‌های TypeScript شما را با سربار صفر زمان اجرا هدایت می‌کند.

Prisma در سال ۲۰۲۴ با مدل آداپتور درایور خود پشتیبانی D1 را اضافه کرد و به موتور کوئری Prisma اجازه می‌دهد از طریق API HTTP D1 در برابر Cloudflare D1 اجرا شود. تعریف شمای Prisma صرف نظر از اینکه Postgres یا D1 را هدف قرار می‌دهید یکسان می‌ماند؛ فقط مقداردهی اولیه مشتری تغییر می‌کند. better-sqlite3، اتصال Node.js به SQLite توسط جاشوآ وایز، همچنان گزینه اصلی برای دسترسی همزمان و با عملکرد بالا به SQLite در Node.js سمت سرور است — طراحی API همزمان آن یک انتخاب عمدی است که با ماهیت همزمان SQLite مطابقت دارد و از سربار async که بسیاری از درایورهای پایگاه داده را آزار می‌دهد جلوگیری می‌کند.

جایی که SQLite واقعاً ضعف دارد

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

حالت WAL به طور قابل توجهی برای بارهای کاری سنگین خواندن با نوشتن‌های گاه‌به‌گاه کمک می‌کند: خوانندگان هرگز نویسنده‌ها را مسدود نمی‌کنند و نویسنده‌ها هرگز خوانندگان را مسدود نمی‌کنند. اما WAL محدودیت اساسی تک‌نویسنده را تغییر نمی‌دهد. اگر گلوگاه شما همزمانی نوشتن است، به یک پایگاه داده با مدیر قفل طراحی شده برای آن نیاز دارید — PostgreSQL، MySQL یا یک سیستم توزیع‌شده مانند CockroachDB.

همچنین هیچ تکرار داخلی وجود ندارد. SQLite استاندارد مفهومی از primary/replica ندارد، هیچ WAL shipping، هیچ شکاف تکرار منطقی. هر راه‌حل تکرار در اکوسیستم — LiteFS، replicaهای جاسازی شده Turso، cr-sqlite — یک لایه است که توسط اشخاص ثالث بر روی SQLite ساخته شده است. این بدان معنی است که راه‌اندازی‌های تکرار پیچیدگی عملیاتی بیشتری نسبت به آنچه به نظر می‌رسد به همراه دارند: شما دو سیستم (SQLite به علاوه لایه تکرار) را مدیریت می‌کنید نه یکی. و تضمین‌های سازگاری متفاوت است: replicaهای جاسازی شده Turso به صورت نهایی سازگار هستند، نه به شدت سازگار — یک نوشتن روی یک replica ممکن است بلافاصله روی replica دیگر قابل مشاهده نباشد.

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

چه زمانی SQLite را انتخاب کنیم و چه زمانی نه

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

PostgreSQL انتخاب درست باقی می‌ماند زمانی که به همزمانی قوی نوشتن، قفل‌گذاری سطح سطر، توپولوژی‌های تکرار پیچیده یا اکوسیستم عمیق افزونه (PostGIS، pgvector، TimescaleDB) که Postgres در سی سال ساخته نیاز دارید. MySQL و MariaDB قلمرو مشابهی را اشغال می‌کنند. یک پایگاه داده توزیع‌شده مانند CockroachDB یا PlanetScale زمانی توجیه می‌شود که به مقیاس‌پذیری نوشتن افقی با تضمین‌های سازگاری قوی در سراسر مناطق نیاز دارید — یک مورد استفاده که SQLite هرگز برای آن طراحی نشده است.

سوال جالب‌تر برای سال ۲۰۲۶ «SQLite در مقابل Postgres» نیست، بلکه «هر کدام در همان سیستم کجا تعلق دارند؟» بسیاری از معماری‌های تولید اکنون از هر دو استفاده می‌کنند: SQLite در لبه برای داده‌های خاص کاربر با نوشتن کم (وضعیت جلسه، تنظیمات برگزیده، فیدهای هر کاربر) و Postgres در مرکز برای داده‌های مشترک با نوشتن زیاد (تراکنش‌ها، موجودی، پیام‌رسانی). پایگاه داده‌ای که ابر انتظارش را نداشت جای خود را در پشته پیدا کرده است — نه با جایگزینی آنچه قبل از آن بود، بلکه با رسیدگی به مواردی که راه‌اندازی یک کلاستر PostgreSQL همیشه پاسخ اشتباه بود.

اشتراک‌گذاری:
SQLite: پایگاه داده‌ای که ابر انتظارش را نداشت — و همچنان در حال پیروزی است | AIO APEX