ನಾವು ಇನ್ನೂ ಡೇಟಾಬೇಸ್ ಬಳಸದೇ ಇರುವುದೇಕೆ
ನಮ್ಮ iPad handwriting appಗಾಗಿ Turso/libSQL ಅನ್ನು ಮೌಲ್ಯಮಾಪನ ಮಾಡಿ, ಎಲ್ಲವನ್ನೂ ಅಳೆದು, flat snapshot files ಆಯ್ಕೆ ಮಾಡಿದೆವು. ಈ workloadಗೆ database ಅಗತ್ಯವಿಲ್ಲ — ಮತ್ತು ಪ್ರತಿಯೊಂದು ಹಂತವೂ ಈಗಾಗಲೇ ಇರುವ ಸಮಸ್ಯೆಗಳಿಗೆ ಮಾತ್ರ ಬೆಲೆ ತೆರಬೇಕು.
Lulucat Notes iPadಗಾಗಿ ಇರುವ handwriting app. ಕಳೆದ ವಾರದವರೆಗೆ ಇದರಲ್ಲಿ ಒಂದೇ canvas ಇತ್ತು; ಎರಡನೇ note ಎಂಬ ಪರಿಕಲ್ಪನೆಯೇ ಇರಲಿಲ್ಲ. ಈಗ ನಾವು ಒಂದು note library ಸೇರಿಸಲು ಸಿದ್ಧರಾಗಿದ್ದೆವು — ಹಲವಾರು documents, ಪ್ರತಿಯೊಂದರಲ್ಲೂ ಹಲವಾರು pages — ಮತ್ತು ಮೊದಲ architectural ಪ್ರಶ್ನೆ storage ಆಗಿತ್ತು.
Database ಒಂದು ಸಹಜ ಉತ್ತರದಂತೆ ಕಂಡಿತು. Notes apps structured data ಅನ್ನು store ಮಾಡುತ್ತವೆ. Structured data databaseಗೆ ಹೋಗುತ್ತದೆ. ನಾವು Turso ಮತ್ತು ಅದರ Swift SDK ಅನ್ನು ಮೌಲ್ಯಮಾಪನ ಮಾಡಿ, iOS simulatorನಲ್ಲಿ run ಮಾಡಿಸಿ, ನಿಜವಾದ stroke dataಗೆ benchmark ಮಾಡಿ, ನಂತರ ಅದನ್ನು ಬಳಸದೇ ಇರಲು ನಿರ್ಧರಿಸಿದೆವು.
ಅದರ ಬದಲು flat files ಆಯ್ಕೆ ಮಾಡಿದೆವು. ನಮಗೆ ಏನು ಕಂಡಿತು ಮತ್ತು ಆ ನಿರ್ಧಾರ ಏಕೆ ತೆಗೆದುಕೊಂಡೆವು ಎಂಬುದು ಇಲ್ಲಿದೆ.

Gabriel Cox ಅವರ ಫೋಟೋ, Unsplash ನಲ್ಲಿ. Unsplash License.
App data ಜೊತೆ app ನಿಜವಾಗಿ ಏನು ಮಾಡುತ್ತದೆ
ಒಂದು handwriting appನ data access pattern ಕಿರಿದಾದ ಮತ್ತು ಊಹಿಸಬಹುದಾದದ್ದು. ಓದುವುದು ಎಂದರೆ ಒಂದು page ತೆರೆಯುವುದು ಮತ್ತು ಅದರ ಪ್ರತಿಯೊಂದು element — ಎಲ್ಲಾ strokes, ಎಲ್ಲಾ images — ಅನ್ನು ಒಂದೇ ಬಾರಿ memoryಗೆ load ಮಾಡುವುದು. Canvas ಎಲ್ಲವನ್ನೂ ಹಿಡಿದಿರುತ್ತದೆ; ಅದು ಎಂದಿಗೂ partial query run ಮಾಡುವುದಿಲ್ಲ. ಬರೆಯುವುದು ಎಂದರೆ ಒಂದು pen stroke ಮುಗಿಸಿ, pageಗೆ ಒಂದು element append ಮಾಡುವುದು. ಅಪರೂಪಕ್ಕೆ user strokeನ ಒಂದು ಭಾಗವನ್ನು erase ಮಾಡಬಹುದು, selection move ಮಾಡಬಹುದು ಅಥವಾ ಏನನ್ನಾದರೂ delete ಮಾಡಬಹುದು; ಆದರೂ ಅವು single-page, single-element operations ಆಗಿಯೇ ಇರುತ್ತವೆ.
Concurrent access ಇಲ್ಲ. ಒಬ್ಬ ವ್ಯಕ್ತಿ ಒಂದೇ ಸಮಯದಲ್ಲಿ ಒಂದೇ documentನ ಒಂದೇ pageನಲ್ಲಿ ಬರೆಯುತ್ತಾನೆ. Cross-document search ಕೂಡ ಇಲ್ಲ — note libraryಗೆ ಪ್ರತಿಯೊಂದು documentಗಾಗಿ title, timestamp, page count ಮತ್ತು cover thumbnail ಮಾತ್ರ ಬೇಕಾಗುತ್ತದೆ; ಇವುಗಳಲ್ಲಿ ಯಾವುದಕ್ಕೂ page content ಓದುವ ಅಗತ್ಯವಿಲ್ಲ.
Queries, indexes ಮತ್ತು concurrency coordinationಗಾಗಿ databases ನಿರ್ಮಿಸಲ್ಪಟ್ಟಿವೆ. ನಮ್ಮ app ಈ ಮೂರರಲ್ಲಿ ಯಾವುದನ್ನೂ ಬಳಸುವುದಿಲ್ಲ.
Turso ಮೌಲ್ಯಮಾಪನ
Tursoನ libSQL engineಗಾಗಿ ಅಧಿಕೃತ Swift SDK ಆಗಿರುವ libsql-swift ಅನ್ನು ನಾವು ಮೌಲ್ಯಮಾಪನ ಮಾಡಿದೆವು.
SDK ಕೆಲಸ ಮಾಡುತ್ತದೆ. ಅದರ ಎಲ್ಲಾ 9 test cases pass ಆಗುತ್ತವೆ. ಅದನ್ನು appನ ಒಂದು copyಗೆ integrate ಮಾಡಿ, iOS simulatorಗಾಗಿ build ಮಾಡಿ, launch ಮಾಡಿ, app sandboxನಲ್ಲಿ local database ಸೃಷ್ಟಿಸಿದೆವು. ಒಂದೇ transactionನಲ್ಲಿ ಪ್ರತಿಯೊಂದೂ 3,400 sampling points ಹೊಂದಿರುವ 100 strokes — 4,080,000 bytes BLOB data — ಬರೆದೆವು. ನಮ್ಮ development Macನಲ್ಲಿ ಇದಕ್ಕೆ ಸುಮಾರು 0.019 seconds ಬೇಕಾಯಿತು.
PRAGMA wal_checkpoint(TRUNCATE) run ಮಾಡಿದ ನಂತರ WAL file zeroಗೆ ಕುಗ್ಗಿತು. ಆಗ main .db file ಒಂದನ್ನೇ ಬೇರೆ locationಗೆ copy ಮಾಡಿ, open ಮಾಡಿ, ಎಲ್ಲ dataಯನ್ನೂ ಹಿಂದಿರುಗಿ ಓದಲು ಸಾಧ್ಯವಾಯಿತು. Engine ಸ್ವತಃ sound ಆಗಿದೆ.
SDKಗೆ costs ಇವೆ. CLibsql.xcframework 161 MB ತೂಗುತ್ತದೆ. Link ಮಾಡಿದ ನಂತರ ನಮ್ಮ Debug simulator build ಸುಮಾರು 1.9 MBನಿಂದ ಸುಮಾರು 8.2 MBಗೆ ಏರಿತು. API synchronous ಮತ್ತು blocking ಆಗಿದ್ದು, Swift Concurrency wrappers ಇಲ್ಲ. Explicit close() method ಇಲ್ಲ. Transaction.commit() throw ಮಾಡುವುದಿಲ್ಲ — ಅದರ underlying C API void return ಮಾಡುತ್ತದೆ. Repositoryಯ README ಈ SDKಗೆ “technical preview” ಎಂಬ label ನೀಡುತ್ತದೆ; ಮತ್ತು ನಮ್ಮ evaluationಗೆ ಸುಮಾರು ಒಂದು ವರ್ಷ ಮುಂಚೆ, July 2025ರಲ್ಲಿ ಅದರ latest commit ಆಗಿತ್ತು.
Turso ecosystemನಲ್ಲಿ ಒಂದು gap ಇದೆ. ಹೊಸ projectsಗಾಗಿ Turso ಈಗ ತನ್ನ ಹೊಸ “Turso Database” engine ಮತ್ತು “Turso Sync” protocol ಅನ್ನು ಶಿಫಾರಸು ಮಾಡುತ್ತದೆ. Turso Syncಗೆ TypeScript, Python, Go ಮತ್ತು Rustಗಾಗಿ client SDKs ಇವೆ. Swiftಗಾಗಿ ಒಂದಿಲ್ಲ. ಹಳೆಯ Embedded Replica mode libsql-swiftನಲ್ಲಿ ಇದೆ, ಆದರೆ ಸಂಪೂರ್ಣ local-first mobile appಗೆ ಬೇಕಾದ offline parameter ಅನ್ನು ಅದರ Swift initializer expose ಮಾಡುವುದಿಲ್ಲ. ಇಂದು libsql-swift ಅಳವಡಿಸಿಕೊಂಡರೆ ನಮಗೆ local SQLite fork ಸಿಗುತ್ತದೆ; Tursoವನ್ನು ವಿಭಿನ್ನಗೊಳಿಸುವ synchronization capabilities ಸಿಗುವುದಿಲ್ಲ.
ಈಗ database ನಮಗೆ ಎಷ್ಟು ವೆಚ್ಚವಾಗುತ್ತದೆ
SDK mature ಆಗಿದ್ದರೂ ಸಹ, ನಮ್ಮ workloadಗೆ ಯಾವುದೇ ಪ್ರಯೋಜನ ಕೊಡದ costs ಅನ್ನು ನಾವು ಇನ್ನೂ ಪಾವತಿಸಬೇಕಾಗುತ್ತಿತ್ತು:
WAL sidecar ಫೈಲ್ಗಳ ನಿರ್ವಹಣೆ. Running database -wal ಮತ್ತು -shm companion files ಸೃಷ್ಟಿಸುತ್ತದೆ. ಒಂದು document copy ಮಾಡಬೇಕಾದರೆ ಮೊದಲು checkpoint ಮಾಡಬೇಕು ಅಥವಾ ಎಲ್ಲಾ ಮೂರು files ಅನ್ನು atomically copy ಮಾಡಬೇಕು. .lnote package ಅನ್ನು Files ಅಥವಾ AirDropಗೆ export ಮಾಡಲು ಈಗ userಗೆ ಕಾಣದ, developer ಮರೆತುಬಿಡಲಾಗದ pre-export step ಬೇಕಾಗುತ್ತದೆ.
ಒಂದು adapter layer. Strokes ಅನ್ನು BLOBಗಳಿಗೆ serialize ಮಾಡಿ, ಮತ್ತೆ deserialize ಮಾಡಬೇಕು. Page elementsಗೆ canvas ನೇರವಾಗಿ render ಮಾಡಬಹುದಾದ natural array order ಇದೆ; database row ordering ಮತ್ತು z-index columns ಪರಿಚಯಿಸುತ್ತದೆ. ಅದೇ dataಯ ಎರಡು representations ನಡುವಿನ translation layer ಅನ್ನು ನಾವು ಬರೆಯಬೇಕು ಮತ್ತು ಪ್ರತಿಯೊಂದು schema changeಗೂ ಅದನ್ನು maintain ಮಾಡಬೇಕು.
161 MB ಗಾತ್ರದ dependency. Debug build 2 MBಕ್ಕಿಂತ ಕಡಿಮೆ ಇರುವ appಗೆ, appಗಿಂತ 80×ಗಿಂತಲೂ ದೊಡ್ಡ dependency ಗಮನಿಸಬೇಕಾದ cost — ವಿಶೇಷವಾಗಿ ಒಂದು ವರ್ಷ inactivity ಹೊಂದಿರುವ “technical preview” ಎಂದು label ಮಾಡಲಾದ dependency ಆಗಿದ್ದರೆ.
ಈ costs hypothetical ಅಲ್ಲ. Dependency link ಆದ ಕ್ಷಣದಿಂದಲೇ ಅವು ಆರಂಭವಾಗುತ್ತವೆ. ಮತ್ತು ಅವು ನಮಗೆ ನಮ್ಮ app ಬಳಸದ capabilities — querying, indexing, concurrent writes — ಖರೀದಿಸಿಕೊಡುತ್ತವೆ.
ನಾವು ಬಿಡುಗಡೆ ಮಾಡಿದ ಪರಿಹಾರ: snapshot file packages
ಒಂದು .lnote document ಒಂದು directory package:
Documents/Notes/<UUID>.lnote/
manifest.json # library cache: title, time, page count, cover
document.json # source of truth: document metadata + page order
pages/
<page-uuid>.content # one snapshot per page
assets/ # document-level shared resources
<asset-uuid>.jpg
thumbnails/
<page-uuid>.jpg # per-page thumbnail; first page doubles as cover
document.json document structureಗೆ source of truth: ಅದರ ID, title, timestamps ಮತ್ತು ಪ್ರತಿಯೊಂದು pageನ canvas size, timestamps ಹಾಗೂ element count ಹೊಂದಿರುವ ordered list of pages. Page content files app ಈಗಾಗಲೇ ಬಳಸುತ್ತಿರುವ ಅದೇ quantized integer encodingನಲ್ಲಿ element array ಅನ್ನು store ಮಾಡುತ್ತವೆ — coordinates ಮತ್ತು radii 0.1-point precisionನಲ್ಲಿ, pressure thousandthsನಲ್ಲಿ, timestamps relative millisecondsನಲ್ಲಿ.
Note library manifest.json ಮತ್ತು cover thumbnails ಅನ್ನು ಮಾತ್ರ ಓದುತ್ತದೆ. ಅದು document.json ಅಥವಾ ಯಾವುದೇ page content ಅನ್ನು ಎಂದಿಗೂ parse ಮಾಡುವುದಿಲ್ಲ. Page ತೆರೆಯುವುದರಿಂದ ಒಂದು .content file load ಆಗುತ್ತದೆ. Stroke data ಅನ್ನು ಮುಟ್ಟುವ ಏಕೈಕ file read ಅದೇ.
Pages write amplification ಅನ್ನು ಪರಿಹರಿಸುತ್ತವೆ
ಒಂದು handwriting appಗೆ page ಎಂಬ concept ಈಗಾಗಲೇ ಇದೆ — user ಯೋಚಿಸುವ unit ಅದೇ, ಅವರು swipe ಮಾಡಿ ಬದಲಾಯಿಸುವ ವಸ್ತುವೂ ಅದೇ. Pageಯನ್ನು persistence unit ಮಾಡಿದರೆ auto-save ಬದಲಾಗಿರುವ pages ಅನ್ನು ಮಾತ್ರ rewrite ಮಾಡುತ್ತದೆ.
ಒಂದು handwriting page — ಉದಾಹರಣೆಗೆ 1,000 ರಿಂದ 2,000 strokes — ನಮ್ಮ quantized formatನಲ್ಲಿ ಸುಮಾರು 3 ರಿಂದ 5 MB occupy ಮಾಡುತ್ತದೆ. 3,400 sampling points ಹೊಂದಿರುವ ಒಂದು 21-stroke recording quantize ಮಾಡಿದಾಗ ಸುಮಾರು 55 KB ಆಗುತ್ತದೆ. Modern hardwareನಲ್ಲಿ ಒಂದು page snapshot ಅನ್ನು flash storageಗೆ ಬರೆಯಲು 10 ರಿಂದ 20 milliseconds ಬೇಕಾಗುತ್ತದೆ. 0.5-second debounce ಜೊತೆ saves userಗೆ ಕಾಣಿಸುವುದಿಲ್ಲ.
Save cost documentನ ಒಟ್ಟು pages ಸಂಖ್ಯೆಯೊಂದಿಗೆ ಅಲ್ಲ, current pageನಲ್ಲಿ ಇರುವ writing ಪ್ರಮಾಣದೊಂದಿಗೆ scale ಆಗುತ್ತದೆ. 200-page notebook, 2-page notebookನಷ್ಟೇ ವೇಗವಾಗಿ save ಆಗುತ್ತದೆ, ಏಕೆಂದರೆ dirty page ಮಾತ್ರ rewrite ಆಗುತ್ತದೆ.
ಪ್ರತಿಯೊಂದು write atomic file operations ಬಳಸುತ್ತದೆ — temporary fileಗೆ write ಮಾಡಿ, ನಂತರ rename ಮಾಡುತ್ತದೆ — ಆದ್ದರಿಂದ save ಮಧ್ಯೆ crash ಆದರೂ truncated page ಸೃಷ್ಟಿಯಾಗುವುದಿಲ್ಲ. Backgroundಗೆ ಪ್ರವೇಶಿಸಿದಾಗ ಎಲ್ಲಾ dirty pages ಅನ್ನು ತಕ್ಷಣ flush ಮಾಡುತ್ತದೆ; single canvas ಇದ್ದಾಗ app ಈಗಾಗಲೇ ಹೊಂದಿದ್ದ behavior ಇದೇ.
Transactions ಇಲ್ಲದೆ consistency
File packagesಗೆ transactions ಇಲ್ಲ, ಆದರೆ ಅದೇ ಉದ್ದೇಶ ಪೂರೈಸುವ clear ownership rules ಇವೆ:
Referencesಗಿಂತ ಮೊದಲು resources. User ಒಂದು image insert ಮಾಡಿದಾಗ asset file ಅನ್ನು ತಕ್ಷಣ assets/ಗೆ ಬರೆಯಲಾಗುತ್ತದೆ. Asset ಅನ್ನು ID ಮೂಲಕ reference ಮಾಡುವ page snapshot ಅನ್ನು debounced auto-save ನಂತರ ಬರೆಯುತ್ತದೆ. Page diskನಲ್ಲಿ ಇಲ್ಲದ asset ಅನ್ನು reference ಮಾಡುವ ಸ್ಥಿತಿ ಯಾವುದೇ ಸಮಯದಲ್ಲೂ ಉಂಟಾಗುವುದಿಲ್ಲ.
Source of truth ಗೆಲ್ಲುತ್ತದೆ. document.json ಮತ್ತು pages/ directory source of truth. manifest.json cache. ಅವುಗಳಲ್ಲಿ ವ್ಯತ್ಯಾಸವಿದ್ದರೆ ಮುಂದಿನ save cache ಅನ್ನು sourceಗೆ ಹೊಂದುವಂತೆ reconcile ಮಾಡುತ್ತದೆ. Thumbnails derived ಆಗಿದ್ದು ಯಾವಾಗ ಬೇಕಾದರೂ regenerate ಮಾಡಬಹುದು.
Dangling referencesಗಿಂತ orphans ಉತ್ತಮ. Crashನ worst outcome ಒಂದು orphan asset — assets/ನಲ್ಲಿರುವ, ಯಾವುದೇ page reference ಮಾಡದ file. Document close ಮಾಡಿದಾಗ orphans cleanup ಆಗುತ್ತವೆ. ವಿರುದ್ಧ ಸ್ಥಿತಿ — page missing file ಅನ್ನು reference ಮಾಡುವುದು — ಸಂಭವಿಸುವುದಿಲ್ಲ, ಏಕೆಂದರೆ reference ಮಾಡುವ page snapshotಗಿಂತ ಮೊದಲು assets ಬರೆಯಲ್ಪಡುತ್ತವೆ.
ಈ rules WAL checkpointing ಮತ್ತು transaction isolationಗಿಂತ ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದು ಸುಲಭ; ಮತ್ತು appನ single-process, single-page access patternಗೆ ನಿಖರವಾಗಿ ಹೊಂದುತ್ತವೆ.
Upgrade path ದಾಖಲಿಸಲಾಗಿದೆ
ಈಗ flat files ಆಯ್ಕೆ ಮಾಡುವುದು ಎಂದರೆ flat files ಅನ್ನು ಎಂದೆಂದಿಗೂ ಆಯ್ಕೆ ಮಾಡುವುದು ಎಂದಲ್ಲ. Package structure ಅನ್ನು ಹೀಗೆ ವಿನ್ಯಾಸಗೊಳಿಸಲಾಗಿದೆ: storage engine upgrade ಮಾಡಿದಾಗ package ಬದಲಾಗದೆ, ಅದರ ಒಳಗಿನದ್ದು ಮಾತ್ರ ಬದಲಾಗುತ್ತದೆ.
Level 1: snapshot + append journal. Write amplification ಎಂದಾದರೂ ಗಮನಾರ್ಹವಾದರೆ — ಉದಾಹರಣೆಗೆ, ಸಾವಿರಾರು strokes ಇರುವ pageನಲ್ಲಿ ನಿರಂತರವಾಗಿ ಬರೆಯುವುದರಿಂದ save delay ಗೋಚರವಾದರೆ — ಪ್ರತಿಯೊಂದು page file snapshot ಮತ್ತು append-only journal ಆಗಿ split ಆಗುತ್ತದೆ. New elements [length][CRC][type][payload] frames ಆಗಿ append ಆಗುತ್ತವೆ. Journal replay ಮಾಡುವಾಗ CRC match ಆಗದ frame ಅನ್ನು discard ಮಾಡಲಾಗುತ್ತದೆ; ಇದರಿಂದ crash safety ಸಿಗುತ್ತದೆ. Journal threshold ಮೀರಿದಾಗ ಅಥವಾ page close ಆದಾಗ ಅದು snapshotಗೆ merge ಆಗುತ್ತದೆ. External dependencies zero ಇರುವ ಸುಮಾರು 200 lines of code ಇದು.
Page-level snapshots ಈಗಾಗಲೇ cross-page write amplification ತೆಗೆದುಹಾಕಿರುವುದರಿಂದ, ಈ level ಬಹಳ ಕಾಲ ಅಗತ್ಯವಿಲ್ಲದಿರಬಹುದು. ಪ್ರತಿಯೊಂದು 0.5 secondsಗೆ 5 MB page rewrite ಮಾಡುವುದು flash write budgetನೊಳಗೆ ಸಾಕಷ್ಟು ಇರುತ್ತದೆ.
Level 2: SQLite database. Appಗೆ ಯಾವಾಗಲಾದರೂ notes across full-text search, per-element synchronization ಅಥವಾ cross-document indexing ಬೇಕಾದರೆ SQLite ಸರಿಯಾದ tool ಆಗುತ್ತದೆ. ಆ ಸಮಯದಲ್ಲಿ ಸಾಧ್ಯತೆಯಿರುವ engine GRDB — mature, source-compiled Swift wrapper, near-zero binary size overhead ಹೊಂದಿರುವುದು. Turso ecosystem — ವಿಶೇಷವಾಗಿ Swiftಗಾಗಿ Turso Sync — ನಿಜವಾದ product need ಆದಾಗ ಮಾತ್ರ libsql-swift ಅನ್ನು ಮರುಪರಿಶೀಲಿಸಲಾಗುತ್ತದೆ.
Migration path mechanical ಆಗಿದೆ: ಪ್ರತಿಯೊಂದು pageಯ element array ಒಂದು strokes / images tableಗೆ map ಆಗುತ್ತದೆ; ಪ್ರತಿಯೊಂದು strokeಗೆ ಒಂದು immutable BLOB (little-endian binaryಯಲ್ಲಿ sampling pointಗೆ 16 bytes). 100 strokesಗೆ 0.019-second benchmark ಈ approach viable ಎಂದು ಖಚಿತಪಡಿಸುತ್ತದೆ. Ship ಮಾಡುವ ಮೊದಲು migration ಹಳೆಯ package ಮತ್ತು ಹೊಸ database ನಡುವೆ element counts ಮತ್ತು asset counts match ಆಗುತ್ತವೆಯೇ, crash recovery, WAL bounds ಮತ್ತು background flush ಎಲ್ಲವೂ pass ಆಗುತ್ತವೆಯೇ ಎಂದು verify ಮಾಡುತ್ತದೆ.
ಯಾವಾಗ ಬೆಲೆ ತೆರಬೇಕು
ಈ ನಿರ್ಧಾರ databases ಬಗ್ಗೆ ತೀರ್ಪಲ್ಲ. SQLite concurrent writers, complex queries ಮತ್ತು shared state ಮೇಲಿನ crash recovery ಅನ್ನು handle ಮಾಡುತ್ತದೆ — ನಮ್ಮ appಗೆ ಈಗ ಇವುಗಳಲ್ಲಿ ಯಾವುದೂ ಅಗತ್ಯವಿಲ್ಲ. Appಗೆ ಇನ್ನೂ ಎದುರಾಗದ problems ಪರಿಹರಿಸುವ capabilitiesಗೆ ಮುಂಚಿತವಾಗಿ ಬೆಲೆ ತೆರವು net loss.
Database costs — dependency, WAL management, adapter layer, binary size — library link ಆದ ಕ್ಷಣದಿಂದ ಆರಂಭವಾಗುತ್ತವೆ. Appಗೆ run ಮಾಡಬೇಕಾದ queries, maintain ಮಾಡಬೇಕಾದ indexes ಅಥವಾ coordinate ಮಾಡಬೇಕಾದ concurrent writers ಬಂದಾಗ benefits ಆರಂಭವಾಗುತ್ತವೆ. ಈ ಹಂತದಲ್ಲಿ ನಮ್ಮ appಗೆ ಈ ಮೂರರಲ್ಲಿ ಯಾವುದೂ ಇಲ್ಲ.
ನಮ್ಮ storage evolutionನ ಪ್ರತಿಯೊಂದು ಹೆಜ್ಜೆಯೂ ಈಗಾಗಲೇ ಕಾಣಿಸಿಕೊಂಡ problemsಗೆ ಮಾತ್ರ ಬೆಲೆ ತೆರಲಿದೆ. Page-level snapshots ಇಂದು ಇರುವ problemಗೆ ಬೆಲೆ ತೆರಿಸುತ್ತವೆ: ಸಂಪೂರ್ಣ file rewrite ಮಾಡದೇ multi-page documents save ಮಾಡುವುದು. Write amplification measurable ಆದರೆ append journal ಆ problemಗೆ ಬೆಲೆ ತೆರಲಿದೆ. Search ಅಥವಾ sync product need ಆದರೆ database ಆ problemಗೆ ಬೆಲೆ ತೆರಲಿದೆ.
Package structure, manifest ಮತ್ತು document schema ಯಾವುದೇ storage engineಗೆ bind ಆಗಿಲ್ಲ. Boundaries ಸರಿಯಾದ ಜಾಗದಲ್ಲಿರುವುದರಿಂದ switching costs ಕಡಿಮೆ. ನಮಗೆ ನಿಜವಾಗಿಯೂ database ಬೇಕಾಗುವ ದಿನ ಬಂದಾಗ, hypothetical problemಗಾಗಿ ಅಲ್ಲ — ಈಗಾಗಲೇ ಅಳೆದು ಕಂಡ specific problemಗಾಗಿ ಅದನ್ನು adopt ಮಾಡುತ್ತೇವೆ.