क्या डेटाबेस सच में ज़रूरी है
(dbpro.app)- सभी डेटाबेस आखिरकार फ़ाइल सिस्टम पर संरचित फ़ाइलों का एक संग्रह होते हैं, इसलिए शुरुआती चरण के applications में फ़ाइलों को सीधे मैनेज करके भी पर्याप्त performance हासिल की जा सकती है
- एक ही server को Go, Bun, Rust में implement करके फ़ाइल स्कैन·in-memory map·disk binary search इन तीन approaches की तुलना करने पर, केवल साधारण फ़ाइल access से भी उच्च throughput हासिल किया जा सकता है
- in-memory map approach ने सबसे अच्छा performance (अधिकतम 169k req/s) दिखाया, जबकि SQLite 25k req/s के साथ स्थिर रहा लेकिन उसमें overhead मौजूद था
- ज़्यादातर services SQLite की एक single file से भी 9 करोड़ DAU स्तर तक संभाल सकती हैं, और शुरुआती product stage में अलग डेटाबेस ज़रूरी नहीं होता
- जब dataset RAM से बड़ा हो जाए या join·multi-condition search·concurrent writes·transaction की ज़रूरत पड़े, तब डेटाबेस अपनाने की आवश्यकता होती है
क्या डेटाबेस सच में ज़रूरी है
- डेटाबेस अंततः फ़ाइलों का ही संग्रह है, SQLite एक single file है, जबकि PostgreSQL directory और process से मिलकर बनता है
- सभी डेटाबेस file system पर read/write करते हैं, और यह code में
open()call करने के समान तरीके से काम करता है - इसलिए असली सवाल “फ़ाइल लिखनी है या नहीं” नहीं, बल्कि “डेटाबेस की फ़ाइल लिखनी है या उसे खुद मैनेज करना है” है
- शुरुआती चरण के कई applications में इसे सीधे मैनेज करके भी पर्याप्त performance पाया जा सकता है
- सभी डेटाबेस file system पर read/write करते हैं, और यह code में
प्रयोग की संरचना
- एक ही HTTP server को Go, Bun(TypeScript), Rust में implement किया गया और दो storage strategies की तुलना की गई
users.jsonl,products.jsonl,orders.jsonlतीन JSONL फ़ाइलों का उपयोगPOST /usersसे create,GET /users/:idसे fetch- benchmark के लिए केवल read path(GET) को target बनाया गया
-
तरीका 1: हर request पर फ़ाइल पढ़ना
- request आने पर फ़ाइल खोली जाती है, सभी lines scan की जाती हैं, JSON parse करके ID match देखा जाता है
- औसतन फ़ाइल का आधा हिस्सा पढ़ना पड़ता है, इसलिए complexity O(n) है
- data बढ़ने के साथ request processing speed तेजी से गिरती है
-
तरीका 2: सब कुछ memory में load करना
- startup पर पूरी फ़ाइल पढ़कर उसे ID-based hash map में रखा जाता है
- write को map और file दोनों में साथ reflect किया जाता है, और read एक single map lookup से O(1) में होता है
- file persistent storage की भूमिका निभाती है, और map index की
- Go का
sync.RWMutexऔर Rust काRwLockparallel reads को support करते हैं
-
तरीका 3: disk पर binary search
- सारा data RAM में लाए बिना तेज lookup के लिए एक बीच का समाधान
- ID के आधार पर sorted data file और fixed-width index file (58 bytes/record) बनाई जाती है
ReadAtसे index को O(log n) में खोजकर, उस offset से single record पढ़ा जाता है- नए records जुड़ने पर sorting टूट जाती है, इसलिए समय-समय पर index rebuild या merge करना पड़ता है
- यह merge pattern LSM-tree के काम करने के तरीके से मिलता-जुलता है
benchmark environment
- dataset size: 10k, 100k, 1M records
- load tool: wrk, 10 सेकंड तक 4 threads और 50 concurrent connections के साथ random GET requests
- उसी machine (Apple M1 Mac mini, macOS 15) पर Go 1.26, Bun 1.3, Rust 1.94 से test
- Go में अतिरिक्त रूप से binary search (disk) और SQLite(modernc.org/sqlite) की भी तुलना की गई
मुख्य परिणाम
- linear scan performance में गिरावट: 1M records पर Go 23 req/s, Bun 19 req/s तक बहुत धीमा हो गया
- binary search (disk): 10k~1M record range में 45k→38k req/s, यानी केवल 15% गिरावट
- OS page cache के प्रभाव से index का ऊपरी हिस्सा हमेशा memory में बना रहा
- SQLite: 25k req/s, औसत latency 2ms के साथ consistent performance बनाए रखा
- binary search, SQLite से लगभग 1.7x तेज था, simple PK lookup में SQLite का overhead दिखा
- memory map approach ने सबसे अच्छा performance दिया: 97k~169k req/s, latency 0.5ms से कम
- Bun, Go से तेज निकला: Bun 106k req/s, Go 97k req/s
- Bun, JavaScriptCore + Zig(uWebSockets) पर आधारित है और libuv को bypass करता है
- Rust linear scan में दबदबे वाला रहा: Go से 3~6x तेज, संभवतः JSON parsing और I/O efficiency के कारण
-
उपयोग के हिसाब से सर्वोत्तम विकल्प
- absolute highest throughput: Rust in-memory map (169k req/s)
- RAM में load किए बिना सर्वश्रेष्ठ: Go binary search (~40k req/s)
- SQL चाहिए तो: SQLite (25k req/s)
- सबसे सरल implementation: Go linear scan (~20 lines of code)
25,000 req/s का मतलब
- सामान्य web traffic के लिए peak:average = 2:1 ratio माना गया
- average 12,500 req/s → peak 25,000 req/s स्तर
- माना गया कि active user प्रति घंटे 10 बार fetch करता है, और peak पर concurrent access rate 10% है
- peak request formula: DAU × 0.000278
- हर approach के saturation DAU का हिसाब
- Go linear scan: 2.8M
- Go binary search: 144M
- SQLite: 90M
- Go in-memory map: 349M
- Bun in-memory map: 381M
- Rust in-memory map: 608M
- ज़्यादातर products इन संख्याओं तक पहुँचते ही नहीं हैं
- उदाहरण: 10,000 SaaS customers → 3 req/s, 100,000 DAU app → 30 req/s
- निष्कर्षतः ज़्यादातर शुरुआती products को डेटाबेस की ज़रूरत नहीं होती
- और ज़रूरत पड़े भी तो SQLite की single file से 9 करोड़ DAU तक संभाला जा सकता है
डेटाबेस कब ज़रूरी होता है
-
जब dataset RAM में समा न सके
- कई करोड़ records पर केवल index के लिए भी कई GB चाहिए होते हैं
- data paging की ज़रूरत पड़ती है, जिसे डेटाबेस अपने आप संभालता है
-
जब ID के अलावा दूसरे fields पर query चाहिए
- multi-condition search के लिए file scan या अतिरिक्त maps चाहिए होते हैं
- कई maps बनाए रखना दरअसल खुद का query engine implement करने जैसा है
-
जब join की ज़रूरत हो
- कई फ़ाइलें पढ़कर उन्हें जोड़ना पड़ता है, और SQL अधिक कुशल रहता है
-
जब कई processes एक साथ write करें
- हर instance का in-memory map अलग हो जाता है, जिससे consistency टूटती है
- ऐसे में external single source of truth चाहिए → यही डेटाबेस की भूमिका है
-
जब entities के बीच atomic write चाहिए
- order creation और inventory deduction दोनों के साथ success/failure की गारंटी चाहिए
- इसके लिए अलग transaction log implement करना पड़ेगा, जबकि DB इसे ACID से हल करता है
- जिन internal tools, side projects, शुरुआती products पर ये constraints नहीं हैं
- वे एक single server की RAM में आराम से चल सकते हैं
- JSONL files को बाद में डेटाबेस में आसानी से migrate किया जा सकता है
परिशिष्ट और code उपलब्धता
- Go, Bun, Rust server code शामिल है
- data seed और benchmark run script(
run_bench.sh) अलग से दिए गए हैं - ZIP file में
go-server/,bun-server/,rust-server/,seed.tsशामिल हैं - script तीन अलग sizes का data seed करती है, फिर wrk से load test चलाकर बंद हो जाती है
DB Pro से संबंधित जानकारी
-
DB Pro** Mac, Windows, Linux के लिए** एक database client है
- query, browsing, management features एक साथ देता है
- collaborative web platform और built-in AI support देता है
- latest version में Val Town की SQLite database connection support जोड़ी गई है
- v1.3.0 में database creation, multi-query editor, PlanetScale Vitess connection features जोड़े गए हैं
26 टिप्पणियां
ये क्या बकवास है
db को क्या लोग सिर्फ़ performance की वजह से इस्तेमाल करते हैं
सच कहूँ तो, लगा शायद कोई नई insight मिलेगी, इसलिए मूल लेख भी देखा, लेकिन ये आखिर है क्या...
मेमोरी महंगी है इसलिए disk इस्तेमाल करने की बात हो, या production संचालन की स्थिरता के लिए, या atomicity जैसी बात— ऐसी basic बातों से शुरुआत करने के बजाय सीधे speed comparison पर उतर आते हैं, तो बस हल्की हँसी निकल जाती है।
'हम DB बेचते हैं, लेकिन DB हमेशा ज़रूरी नहीं होता!' — article लिखते हुए ऐसी बात भी बिना झिझक कर देना, पता नहीं marketing करना चाहते हैं या क्या sigh... सकारात्मक नज़र से देखने की कोशिश करूँ तब भी कभी-कभी थोड़ा cynical हो जाता हूँ।
चलो, कम से कम benchmark तो मिला, ऐसा मान लेते हैं।
मुझे लगता है कि यह बहुत अच्छा लेख है। खासकर ऐसे
'संख्याओं'वाले सामग्री सचमुच दुर्लभ होते हैं। आज के दौर में ऐसे डेवलपर आसानी से नहीं मिलते जिन्हें कम-से-कम इतना भी अंदाज़ा हो कि हम जो कोड बनाते हैं और जो tech stack इस्तेमाल करते हैं, उनमें किस तरह का overhead होता है; इसलिए इसे पढ़कर अच्छा लगा।मैं भी सहमत हूँ। मुझे लगता है कि यह Mechanical sympathy या development में गति और संतुलन को नियंत्रित करने के लिए ज़रूरी intuition देने वाली सामग्री है। ठीक
Latency Numbers Every Programmer Should Knowकी तरह।और मुझे यह लेख ऐसा नहीं लगा कि वह किसी एक खास दिशा को बिना शर्त बेहतर बता रहा है। बल्कि लेख में उल्लेख किए गए सभी तरीकों ने जो संख्याएँ दिखाईं, वे "ज़्यादातर business में ज़रूरत से कहीं अधिक performance" जैसी लगीं, इसलिए मैंने इसे इस तरह पढ़ा कि समस्या-स्थिति के हिसाब से उपयुक्त तरीका चुनना चाहिए।
और जवाबों में छिपे रत्न तो बोनस हैं।
अगर ऐसा करने की कोई वजह है, तो इस पर विचार करना पड़ सकता है, है ना? जैसे performance constraints बहुत ही कड़े हों।
लेकिन ज़्यादातर मामलों में क्या इसे खास तौर पर चुनने की कोई वजह है? ऐसा भी नहीं है कि DB के अपने फायदे नहीं हैं..
यह बस सोच में बदलाव की तरह पढ़ा जाता है, लेकिन आप सब काफ़ी संवेदनशील हो रहे हैं।
सही कहा। इसे इस सुझाव की तरह देखा जा सकता है कि बिज़नेस के शुरुआती चरण में, जब यूज़र ज़्यादा न हों, तो DB खरीदने या चीज़ों को बेवजह जटिल बनाने के बजाय सिर्फ़ बेसिक file I/O के सहारे भी बिज़नेस के टिकने तक पहुँचा जा सकता है।
मैं भी सहमत हूँ। कई बार services में DB को जरूरत से ज़्यादा अहमियत दी जाती है, और कभी-कभी normalization टूट जाए तो जैसे बहुत बड़ा नुकसान हो जाएगा, इस डर से design में जरूरत से ज़्यादा investment भी कर दी जाती है.
मुद्दा यह नहीं है कि DB का इस्तेमाल ही न किया जाए, बल्कि बस इतना कि हम यह सोच ताज़ा करें कि हम इसका इस्तेमाल क्यों कर रहे थे और service की असली बुनियाद आखिर क्या है.
आखिरकार हमेशा balance ही सबसे ज़रूरी होता है.
जिस क्षण आप SQLite को production server के लिए चुनते हैं, उसी क्षण से यह लगातार सोचना पड़ता है कि इसे कब बदलना है।
पहले DB की अपनी लागत (server खरीद लागत, IDC, license लागत आदि) महंगी होती थी, इसलिए इस पर विचार करना सार्थक था,
लेकिन आजकल तो तथाकथित एक क्लिक में सेटअप हो जाता है, तो क्या सच में इस पर चिंता करने की ज़रूरत है?
अभी भी DB महंगा है।
यह एकदम पारंपरिक armchair coding है।
बिलकुल, अगर यह "शुरुआती चरण का प्रोजेक्ट या छोटे पैमाने का application" है, तो database की ज़रूरत नहीं भी हो सकती है। सिर्फ database ही नहीं, दूसरे elements भी लगभग कुछ भी रखकर काम चल सकता है। असली मुद्दा तब है जब scale बढ़ता है। यह बस मज़े के लिए numbers देखने वाली पोस्ट है।
https://hackers.pub/@gnh1201/2025/…
कभी-कभी अलग से database install करने की ज़रूरत नहीं होती। हालांकि यह सिर्फ Windows तक सीमित है...
शीर्षक देखकर ज़ोर से हँसी आ गई।
कभी-कभी मैं यह सोचता हूँ कि क्या मुख्य entities की persistence को सचमुच RDBMS के जरिए ही सुनिश्चित करना ज़रूरी है। आखिर SSOT उपलब्ध कराने के लिए कुछ वैकल्पिक(?) तकनीकें भी काफ़ी हैं।
अगर Sqlite टूट जाए तो कोई समाधान नहीं..
क्या ऐसे case होते हैं जहाँ sqlite खराब हो जाता है? जानना चाहता हूँ। असामान्य file move या delete को छोड़कर।
Hacker News राय
यह लेख मुझे सच में बहुत पसंद आया। यह अच्छी तरह दिखाता है कि कंप्यूटर कितने तेज़ हैं
लेकिन आख़िरी हिस्से के निष्कर्ष से मैं सहमत नहीं हूँ। लेखक ने कहा कि यह उन ऐप्स पर लागू नहीं होता जहाँ “कई processes को एक साथ write करना पड़ता है”, लेकिन असल में शुरुआती चरण के products में भी अक्सर cron या message queue जैसे अलग workers को एक साथ write करना पड़ता है
इसे इस तरह भी बनाया जा सकता है कि सिर्फ main server ही write करे, लेकिन इससे architecture complexity बढ़ जाती है
इसलिए pure scale के नज़रिए से मैं लेखक से सहमत हूँ, लेकिन थोड़ा व्यापक रूप से देखें तो database इस्तेमाल करना बेहतर लगता है। खासकर SQLite एक समझदारी भरा विकल्प है
अगर scale चाहिए, तो frequently accessed data को memory में cache किया जा सकता है। मैं SQLite + in-memory cache का combination इस्तेमाल करता हूँ
S3 कभी-कभी काम आ जाता है, लेकिन फिर भी उसे पूर्ण विकल्प की तरह इस्तेमाल करने में कई सीमाएँ हैं
अलग DB server manage या backup करने की ज़रूरत नहीं पड़ती, इसलिए यह कहीं ज़्यादा सरल और सस्ता है
मुझे SQLite बहुत पसंद है, लेकिन यह हर समस्या का जवाब नहीं है
client-side dictionary app बनाते समय मैंने SQLite wasm port इस्तेमाल किया था, लेकिन DB file उम्मीद से बड़ी निकली, compression भी अच्छा नहीं था और loading भी धीमी थी
आखिरकार मैंने मूल TSV file से सीधे index बनाया, उसे zstd से compress किया, और wasm में हर बार decompress करने का तरीका अपनाया। यह SQLite से काफ़ी तेज़ निकला
module size भी 800KB से घटकर 52KB हो गया, और कई instances एक साथ चलाने पर भी बोझ नहीं पड़ा
string search के लिए मैंने stringzilla इस्तेमाल किया, जो अविश्वसनीय रूप से तेज़ है
SQLite बेहतरीन है, लेकिन हर स्थिति का सही उत्तर नहीं है
SQLite benchmark में optimization कम है
बस
इतना जोड़ने भर से मेरी मशीन पर performance 27,700 r/s से बढ़कर 89,687 r/s हो गई
prepared statement या timestamp को int में बदलकर भी देखा, लेकिन बड़ा फ़र्क नहीं पड़ा
लेख ठीक था, लेकिन “हर DB file system को open() के ज़रिए access करता है” वाला हिस्सा सही नहीं है
SQLite जैसे apps mmap का इस्तेमाल करके file को सीधे memory space में map करते हैं। इस तरीके में syscall को bypass किया जा सकता है और access काफ़ी तेज़ होता है
लेख के बाद के हिस्से में पूरी file को memory में पढ़ने की प्रक्रिया समझाई गई है, लेकिन अगर mmap का इस्तेमाल किया जाता तो शायद बेहतर होता
लेकिन mmap हमेशा बेहतर है, ऐसा मानना भी मुश्किल है। कुछ लोग OS API पर निर्भर रहने के बजाय application logic में चीज़ों को सीधे संभालना पसंद करते हैं
संबंधित paper के लिए CMU का mmap अध्ययन देखें
“open() की तरह काम करता है” कहना थोड़ा सरलीकरण है, लेकिन तकनीकी रूप से ग़लत नहीं है
बहुत पहले मैंने Perl में एक छोटा sales web app बनाया था, लेकिन ISP server पर कुछ भी install नहीं कर सकता था, इसलिए file-based hash का इस्तेमाल किया
client ने 20 साल से ज़्यादा समय तक उसी को वैसे ही इस्तेमाल किया, फिर उसके निधन के बाद परिवार ने उसे संभाला और Wordpress पर बदल दिया
आख़िरी बार देखने पर orders कई लाख थे, फिर भी performance ठीक-ठाक थी
hardware की प्रगति की वजह से यह जुगाड़ जैसा ढांचा उम्मीद से कहीं ज़्यादा समय तक चल गया। आज बनाता तो शायद SQLite भी काफ़ी होता
अगर आप खुद storage implement करें, तो समझ आता है कि DB कैसे काम करता है
indexes और data structures को efficiently संभालना पड़ता है, और अंत में निष्कर्ष यही निकलता है कि “अगर यह खिलवाड़ नहीं था, तो शुरू से DB इस्तेमाल करना चाहिए था”
Relational Databases Aren’t Dinosaurs, They’re Sharks
छोटे apps में मिलने वाले मामूली फ़ायदे से कहीं बड़ा नुकसान है पहिया फिर से बनाने में समय बर्बाद करना
Cretaceous काल में भी shark लगभग आज जैसी ही थीं, और उसके बाद भी बिना बड़े बदलाव के जीवित रहीं
दूसरी ओर dinosaur, pterosaur और mosasaur ग़ायब हो गए, लेकिन shark, crocodile और बड़े साँप optimized design की वजह से लगभग उसी रूप में आज तक बने हुए हैं
मुझे लगता है relational DB भी कुछ ऐसी ही चीज़ है
ऐसे लेख पढ़ना आनंददायक है
फिर भी मैं अब भी 99% मामलों में SQL और transactions वाले DB का इस्तेमाल करता हूँ
हाल में एक personal project में मैंने YAML file-आधारित simple file system से data manage करके देखा, और मेरे scale पर performance की कोई समस्या नहीं हुई
इंसानों के पढ़ पाने और diff कर पाने की सुविधा performance से ज़्यादा महत्वपूर्ण थी
फिर भी ज़्यादातर मामलों में मैं query language और guaranteed consistency वाले DB को ही चुनूँगा
अंत में DB के features और ACID guarantees की ज़रूरत पड़ ही जाती है
जब भी कभी legacy flat-file store इस्तेमाल करना पड़ता है, consistency, transaction और query language को ज़बरदस्ती जोड़ने में बहुत मेहनत लगती है। आखिरकार यह फिर से पहिया बनाने जैसा ही है
जैसे ही atomicity की ज़रूरत पड़ती है, DB अनिवार्य हो जाता है
file system के ऊपर atomic writes implement करना बहुत नाज़ुक काम है
इसी वजह से कई DB crash होने पर data corruption की समस्या झेलते हैं। पहले Windows पर RocksDB के साथ ऐसा हुआ था
इसे खुद implement करना पागलपन जैसा लगता है। OS API के साथ safely write करना सीखना अच्छा है, लेकिन आजकल यह बहुत niche skill बन चुका है
और ऊपर से यह भी संभव है कि आपका successor इसे maintain ही न कर पाए। अंत में DB पर ही जाना पड़ेगा
कम से कम उसी file system के भीतर temporary file में लिखना, fsync करना, फिर rename से replace करना चाहिए
पूरे DB को temporary file में लिखकर flush करने के बाद move से replace करें, तो Unix में यह atomic होता है
लेकिन यह बिलकुल scale नहीं करता। छोटे update पर भी पूरी file फिर से लिखनी पड़ती है, और lock management भी चाहिए। यह ACID का सिर्फ कुछ हिस्सा हल करता है
वैसे OLAP DB DuckDB out-of-core workloads में भी शानदार काम करता है
official docs link
फ़्रिज के बिना भी जिया जा सकता है, लेकिन असुविधा तो होगी ही।
जब फ़्रिज इस्तेमाल कर सकते हैं, तो उसे न इस्तेमाल करने की कोई वजह नहीं है।
क्या आप Noh-rani हैं, इल्बे समर्थक?
अगर मैं ना कहूँ तो क्या हर कोई Ilbe हो जाता है? मैं Gyeongsang-do का रहने वाला हूँ, तो क्या?
मैं इसकी रिपोर्ट करना चाहता/चाहती हूँ, लेकिन रिपोर्ट करने का तरीका नहीं जानता/जानती। आह.
लगता है यह टिप्पणी कोरियाई डेवलपर्स की बंद सोच और GeekNews के स्तर, दोनों को दिखाती है।
वह स्तर आखिर किस तरह का स्तर है, तुमने उस स्तर का आकलन किस वजह से किया, यह logic/fact/science/statistics में से कम-से-कम 2 चीज़ों का इस्तेमाल करके बताओ haan haan
हाहा, सिर्फ शब्द देखकर ही समझ आता है कि यह DC Inside, Ilbe, Fmkorea टाइप का यूज़र है, ध्यान मत दीजिए।