MongoDB: Storage Management

MongoDB: Storage Management

Table of Contents



1. The Big Picture

In Oracle, you think in terms of tablespaces, datafiles, segments, extents, and blocks. MongoDB is much simpler. There are no tablespaces, no datafiles to manage, and no extent allocation. Here is the high-level comparison:


ORACLE ARCHITECTURE                     MONGODB ARCHITECTURE
─────────────────                       ────────────────────

┌─────────────────────┐                ┌─────────────────────┐
│      INSTANCE       │                │      mongod         │
│  ┌───────────────┐  │                │  ┌───────────────┐  │
│  │   SGA         │  │                │  │ WiredTiger    │  │
│  │  Buffer Cache │  │                │  │ Cache         │  │
│  │  Shared Pool  │  │                │  │ (50% of RAM   │  │
│  │  Redo Buffer  │  │                │  │  by default)  │  │
│  └───────────────┘  │                │  └───────────────┘  │
│  ┌───────────────┐  │                │  ┌───────────────┐  │
│  │   PGA         │  │                │  │ Per-connection│  │
│  │  Sort Area    │  │                │  │ memory        │  │
│  └───────────────┘  │                │  └───────────────┘  │
└─────────┬───────────┘                └─────────┬───────────┘
          │                                      │
          ▼                                      ▼
┌─────────────────────┐                ┌─────────────────────┐
│   DATAFILES (.dbf)  │                │  WiredTiger Files   │
│  Tablespace SYSTEM  │                │  collection-xxx.wt  │
│  Tablespace USERS   │                │  index-xxx.wt       │
│  Redo Logs          │                │  journal/WiredTiger │
│  Control Files      │                │  WiredTiger.wt      │
└─────────────────────┘                └─────────────────────┘

The key difference: In Oracle, you create tablespaces and datafiles manually. In MongoDB, the storage engine (WiredTiger) manages all files automatically. You just create a database and a collection, and MongoDB handles the rest.

Terminology mapping:

OracleMongoDBSimple Explanation
DatabaseDatabaseSame concept. A logical container. One mongod can host many databases.
TablespaceDoes not existMongoDB has no tablespaces. All data for a database lives in one directory.
Datafile (.dbf).wt files (WiredTiger)MongoDB creates .wt files automatically. You never manage them manually.
TableCollectionA group of documents. Created automatically on first insert.
RowDocument (BSON)A single record. Stored as a BSON (binary JSON) object. Max 16 MB.
ColumnFieldA key-value pair inside a document. No fixed schema required.
IndexIndexSame concept. B-tree structure. Every collection has a default _id index.
Block (8 KB)Page (4 KB default)The unit of I/O. WiredTiger reads and writes in pages.

2. Files on Disk

In Oracle, you know exactly where your data lives: /u01/oradata/MYDB/system01.dbf, users01.dbf, etc. In MongoDB, all files live in the dbPath directory (default: /var/lib/mongodb on Linux or C:\data\db on Windows).

Here is what you will see inside the dbPath:


/var/lib/mongodb/                  ← dbPath (like ORACLE_BASE/oradata)
│
├── WiredTiger                     ← storage engine identifier file
├── WiredTiger.wt                  ← main metadata file (like control file)
├── WiredTiger.lock                ← lock file (prevents two mongod processes)
├── WiredTiger.turtle              ← metadata checkpoint info
│
├── collection-0-xxx.wt            ← collection data files
├── collection-2-xxx.wt            ← (one or more per collection)
├── collection-4-xxx.wt            ← (created automatically)
│
├── index-1-xxx.wt                 ← index files
├── index-3-xxx.wt                 ← (one or more per index)
│
├── journal/                       ← journal directory (like redo logs)
│   ├── WiredTigerLog.0000000001
│   ├── WiredTigerLog.0000000002
│   └── WiredTigerLog.0000000003
│
├── diagnostic.data/               ← monitoring data (like AWR snapshots)
│
├── myFirstDB/                     ← (if using directoryPerDB option)
│   ├── collection-xxx.wt
│   └── index-xxx.wt
│
└── _mdb_catalog.wt                ← catalog of all databases and collections
                                   ← (like the data dictionary)

Key points for Oracle DBAs:

  • No manual file management: You never create, resize, or add datafiles. WiredTiger creates and grows .wt files automatically as needed.
  • No pre-allocation: Oracle pre-allocates datafiles (e.g., 1 GB). MongoDB files grow dynamically. This saves disk space but means file growth happens during writes.
  • One directory per database (optional): By default, all databases share the same directory. If you set storage.directoryPerDB: true in the config file, each database gets its own subdirectory. This is similar to Oracle’s OFA structure but optional.
  • File naming: The file names like collection-0-xxx.wt are internal identifiers. You cannot tell which collection a file belongs to by looking at the name. Use db.stats() or collStats to see storage details.
  • Do NOT touch these files: Never copy, move, rename, or delete .wt files while mongod is running. This will corrupt the database. Always use mongodump and mongorestore for backups (like RMAN in Oracle).

Oracle vs MongoDB file comparison:

OracleMongoDB
system01.dbf, users01.dbfcollection-xxx.wt
redo01.log, redo02.logjournal/WiredTigerLog.xxx
control01.ctlWiredTiger.wt + _mdb_catalog.wt
temp01.dbfNo separate temp files (sorts spill to disk in the same dbPath)
undotbs01.dbfNo separate undo (MVCC is handled inside the B-tree)

3. WiredTiger Cache (Your SGA)

In Oracle, the SGA (System Global Area) is the shared memory area that includes the buffer cache, shared pool, and redo log buffer. You size it with SGA_TARGET or MEMORY_TARGET.

In MongoDB, the equivalent is the WiredTiger cache. It is the in-memory area where WiredTiger keeps frequently accessed data pages and index pages.


ORACLE SGA                          WIREDTIGER CACHE
──────────                          ────────────────

┌──────────────────────┐            ┌──────────────────────┐
│ Buffer Cache         │            │ Data pages           │
│ (table and index     │            │ (collection data)    │
│  blocks from disk)   │            │                      │
├──────────────────────┤            ├──────────────────────┤
│ Shared Pool          │            │ Index pages          │
│ (parsed SQL, plans)  │            │ (all index B-trees)  │
├──────────────────────┤            ├──────────────────────┤
│ Redo Log Buffer      │            │ (journal is written  │
│ (redo entries before │            │  directly to disk,   │
│  flush to redo log)  │            │  not cached here)    │
└──────────────────────┘            └──────────────────────┘

Default size:                       Default size:
  SGA_TARGET = you set it             50% of (RAM - 1 GB)
                                      minimum 256 MB

How to check and set the cache size:

// Check current cache usage
db.serverStatus().wiredTiger.cache

// Key fields to look at:
// "bytes currently in the cache"        ← how much data is in memory
// "maximum bytes configured"            ← the cache size limit
// "tracked dirty bytes in the cache"    ← modified pages not yet on disk
// "pages read into cache"               ← disk reads (like physical reads)
// "pages written from cache"            ← disk writes (like DBWR writes)

To set the cache size, edit the MongoDB config file (/etc/mongod.conf):

storage:
  wiredTiger:
    engineConfig:
      cacheSizeGB: 4    # Set to 4 GB (like setting SGA_TARGET = 4G)

Rule of thumb (like Oracle’s 80% rule):

  • If MongoDB is the only application on the server, leave the default (50% of RAM). WiredTiger also uses the OS filesystem cache, so the effective cache is larger than the WiredTiger cache alone.
  • If MongoDB shares the server with other applications, set cacheSizeGB explicitly to avoid memory pressure.
  • Do NOT set the cache to more than 60–70% of total RAM. The OS needs memory for the filesystem cache and other processes.

Important difference from Oracle: In Oracle, if the buffer cache is too small, you get lots of physical reads and performance drops. In MongoDB, the same thing happens — if the WiredTiger cache is too small, WiredTiger must read pages from disk more often. You can monitor this with db.serverStatus().wiredTiger.cache["pages read into cache"]. A high and growing number means your cache may be too small for your workload.

4. Journal and Checkpoints (Your Redo Logs)

This is the most important concept for durability. If you understand Oracle redo logs and checkpoints, you already understand 90% of MongoDB’s journal.


ORACLE                              MONGODB
──────                              ───────

1. User does INSERT/UPDATE/DELETE   1. User does insert/update/delete

2. Change goes to buffer cache      2. Change goes to WiredTiger cache
   (in memory)                         (in memory)

3. Redo entry written to            3. Journal entry written to
   redo log buffer                     journal buffer

4. LGWR flushes redo buffer         4. WiredTiger flushes journal
   to redo log files on disk           to journal files on disk
   (every 3 seconds, or at            (every 100 ms by default,
    commit, or when 1/3 full)          or immediately if j:true)

5. DBWR writes dirty blocks         5. Checkpoint writes dirty pages
   from buffer cache to                from WiredTiger cache to
   datafiles on disk                   .wt files on disk
   (incremental checkpoint)            (every 60 seconds by default)

6. After checkpoint, old redo       6. After checkpoint, old journal
   logs can be overwritten             files can be removed

Journal details:

Oracle Redo LogsMongoDB Journal
Location: redo01.log, redo02.logLocation: journal/WiredTigerLog.xxx
Size: you set it (e.g., 500 MB each)Size: max 100 MB per file, auto-rotated
Groups: minimum 2 groupsFiles: multiple files, old ones removed after checkpoint
Content: physical block changesContent: logical operations (compressed)
Flush trigger: commit, 3 sec, 1/3 fullFlush trigger: 100 ms interval, or j:true
ARCHIVELOG mode for backupJournal always on (cannot be disabled in replica sets)

Checkpoint details:

In Oracle, a checkpoint writes all dirty blocks from the buffer cache to the datafiles. In MongoDB, a checkpoint writes all dirty pages from the WiredTiger cache to the .wt files.

  • Frequency: MongoDB checkpoints every 60 seconds by default (configurable). Oracle uses incremental checkpoints that happen continuously.
  • What happens: During a checkpoint, WiredTiger writes all modified (dirty) pages to disk. After the checkpoint completes, the journal entries before the checkpoint are no longer needed and can be removed.
  • Crash recovery: If mongod crashes, on restart WiredTiger replays the journal from the last checkpoint. This is exactly like Oracle’s instance recovery (roll forward from the last checkpoint using redo logs).

Write concern and the journal (like COMMIT in Oracle):

In Oracle, a COMMIT forces LGWR to flush the redo buffer to disk. In MongoDB, the write concern controls when the write is acknowledged:

Write ConcernWhat It MeansOracle Equivalent
w: 1 (default)Primary has the data in memory. Journal may not be flushed yet (up to 100 ms delay).Like a commit where LGWR has not yet flushed (not possible in Oracle — commit always flushes redo).
w: 1, j: truePrimary has flushed the journal to disk. Safest single-node option.Exactly like Oracle COMMIT (LGWR flushes redo to disk).
w: "majority"Majority of replica set members have the data.Like Data Guard SYNC mode (commit waits for standby acknowledgment).
w: 0Fire and forget. No acknowledgment.No Oracle equivalent (Oracle always acknowledges).

5. Space Management and Compression

In Oracle, you manage space with tablespaces, autoextend, quotas, and segment space management (ASSM). In MongoDB, space management is almost entirely automatic. Here is what you need to know:

5a. How Space Grows

WiredTiger files grow automatically as you insert data. You do not pre-allocate space. Think of it like an Oracle datafile with AUTOEXTEND ON and no MAXSIZE — it just keeps growing until the disk is full.


ORACLE                                MONGODB
──────                                ───────

CREATE TABLESPACE users               (nothing — just insert data)
  DATAFILE '/u01/users01.dbf'
  SIZE 1G AUTOEXTEND ON
  MAXSIZE 10G;

You monitor:                          You monitor:
  DBA_DATA_FILES                      db.stats().storageSize
  DBA_FREE_SPACE                      db.stats().freeStorageSize
  DBA_SEGMENTS                        db.collection.stats().storageSize

5b. Compression (Your Secret Weapon)

This is where MongoDB shines compared to Oracle. WiredTiger compresses data by default, so your data on disk is much smaller than the actual data in memory.

LevelDefault AlgorithmOracle Equivalent
Collection dataSnappy (fast, moderate compression)Advanced Row Compression (requires license)
IndexesPrefix compression (reduces duplicate key prefixes)Index Key Compression (ALTER INDEX … COMPRESS)
JournalSnappyRedo log compression (12c+, not common)

Available compression options:

  • none — no compression (fastest CPU, most disk space)
  • snappy — default for collections and journal (good balance)
  • zlib — better compression than Snappy but uses more CPU
  • zstd — best compression, available from MongoDB 4.2 (good for cold data)

Real-world example: If you insert 10 GB of JSON data into MongoDB with Snappy compression, the .wt files on disk may be only 3–5 GB. In Oracle, the same data in an uncompressed table would take the full 10 GB (plus index space).

5c. Space After Deletes (The Fragmentation Problem)

This is very similar to Oracle. When you delete rows in Oracle, the space in the data blocks is freed but the datafile does not shrink. The same thing happens in MongoDB.


BEFORE DELETE                         AFTER DELETE (1 million docs removed)
─────────────                         ──────────────────────────────────────

storageSize:  10 GB                   storageSize:  10 GB  ← same!
dataSize:      8 GB                   dataSize:      3 GB  ← smaller
free space:    2 GB                   free space:    7 GB  ← more holes

The .wt files do NOT shrink.          The space is reused for future
This is like Oracle HWM.              inserts, like Oracle free blocks.

How to reclaim space:

MethodMongoDB CommandOracle Equivalent
Compact one collectiondb.runCommand({ compact: "students" })ALTER TABLE students SHRINK SPACE
Drop and recreatedb.students.drop() then re-insertTRUNCATE TABLE or DROP + CREATE
Initial sync (replica set)Resync the secondary from the primaryRebuild the standby database

Warning: The compact command locks the collection during the operation. Run it during a maintenance window, just like you would schedule ALTER TABLE ... MOVE in Oracle.

6. Useful Storage Commands

Here are the commands you will use most often as a DBA. Think of these as your MongoDB versions of DBA_DATA_FILES, DBA_SEGMENTS, and V$SGA.

6a. Database-Level Stats (like DBA_DATA_FILES)

// Overall database size
db.stats()

// Key fields in the output:
// "db"             → database name
// "collections"    → number of collections (like number of tables)
// "objects"        → total number of documents (like total rows)
// "dataSize"       → uncompressed data size in bytes
// "storageSize"    → actual disk space used (after compression)
// "indexSize"      → total size of all indexes
// "fileSize"       → total size of all .wt files (deprecated in newer versions)

Example output:

{
  "db": "myFirstDB",
  "collections": 5,
  "objects": 1500000,
  "dataSize": 2147483648,       // 2 GB uncompressed
  "storageSize": 858993459,     // 800 MB on disk (compression!)
  "indexSize": 268435456,       // 256 MB for indexes
  "ok": 1
}

6b. Collection-Level Stats (like DBA_SEGMENTS)

// Stats for a specific collection
db.students.stats()

// Or using the aggregation framework (MongoDB 5.0+)
db.students.aggregate([ { $collStats: { storageStats: {} } } ])

// Key fields:
// "count"          → number of documents (like NUM_ROWS)
// "size"           → uncompressed data size
// "storageSize"    → disk space used
// "avgObjSize"     → average document size in bytes
// "nindexes"       → number of indexes
// "totalIndexSize" → total index size

6c. Index Stats (like DBA_INDEXES)

// List all indexes on a collection
db.students.getIndexes()

// Size of each index
db.students.stats().indexSizes
// Example output:
// { "_id_": 12345678, "age_1": 8765432, "name_1": 9876543 }

// Detailed index usage stats (which indexes are actually used?)
db.students.aggregate([ { $indexStats: {} } ])
// This is like V$OBJECT_USAGE in Oracle — it tells you
// which indexes are being used and which are not.

6d. Cache and Memory Stats (like V$SGA / V$BUFFER_POOL)

// WiredTiger cache details
db.serverStatus().wiredTiger.cache

// Key fields:
// "maximum bytes configured"         → cache size limit (like SGA_TARGET)
// "bytes currently in the cache"     → current usage
// "tracked dirty bytes in the cache" → modified pages (like dirty buffers)
// "pages read into cache"            → disk reads (like physical reads)
// "pages written from cache"         → disk writes (like DBWR writes)

// Overall memory usage
db.serverStatus().mem
// "resident"  → actual RAM used by mongod (in MB)
// "virtual"   → virtual memory (in MB)

6e. Disk Space (like df -h or ASM disk groups)

// MongoDB does not have a built-in "disk free" command.
// Use the OS command:
// Linux:   df -h /var/lib/mongodb
// Windows: dir C:\data\db

// But you can check the total storage used by all databases:
db.adminCommand({ listDatabases: 1 })
// This lists every database and its size on disk.

6f. Quick Reference Card

What You Want to KnowMongoDB CommandOracle Equivalent
Total database sizedb.stats()SELECT SUM(bytes) FROM dba_segments
Collection sizedb.students.stats()DBA_SEGMENTS WHERE segment_name = 'STUDENTS'
Document countdb.students.countDocuments({})SELECT COUNT(*) FROM students
Index listdb.students.getIndexes()DBA_INDEXES WHERE table_name = 'STUDENTS'
Index usagedb.students.aggregate([{$indexStats:{}}])V$OBJECT_USAGE
Cache usagedb.serverStatus().wiredTiger.cacheV$SGA / V$BUFFER_POOL_STATISTICS
All databases and sizesdb.adminCommand({listDatabases:1})DBA_DATA_FILES GROUP BY tablespace_name
Current operationsdb.currentOp()V$SESSION / V$SQL
Server statusdb.serverStatus()V$SYSSTAT / V$INSTANCE
Reclaim spacedb.runCommand({compact:"students"})ALTER TABLE students SHRINK SPACE

7. Oracle Comparison Table

A complete side-by-side reference for Oracle DBAs:

ConceptOracleMongoDB
Storage engineOracle Database (proprietary)WiredTiger (default since 3.2)
DatabaseOne database per instance (or CDB/PDB in 12c+)Many databases per mongod process
TablespaceLogical storage container (SYSTEM, USERS, TEMP, UNDO)Does not exist
Datafile.dbf files, manually created and sized.wt files, automatically created and grown
Block / Page size8 KB default (configurable: 2K–32K)4 KB internal page (not configurable)
Row / Document limit~8 KB per row (non-LOB), LOBs stored out-of-line16 MB per document
SchemaFixed (CREATE TABLE with columns and types)Flexible (schema validation is optional)
Memory (SGA)SGA_TARGET / MEMORY_TARGETwiredTiger.cacheSizeGB (default: 50% of RAM – 1 GB)
Buffer cachePart of SGA, stores data blocksWiredTiger cache, stores data and index pages
Shared poolParsed SQL, execution plans, dictionary cacheNo equivalent (no SQL parsing needed)
Redo logsOnline redo logs (groups, members, archivelog)Journal (journal/ directory, auto-rotated)
Redo flushLGWR: at commit, every 3 sec, 1/3 fullEvery 100 ms, or immediately with j:true
CheckpointIncremental (continuous), full (log switch)Every 60 seconds (configurable)
UndoUndo tablespace, undo segments, undo_retentionNo separate undo (MVCC in the B-tree itself)
Temp spaceTEMP tablespace for sorts and hash joinsNo separate temp (sorts spill to dbPath if > 100 MB)
CompressionOptional (HCC, ACO — requires license)On by default (Snappy for data, prefix for indexes)
Space reclamationSHRINK SPACE, MOVE, TRUNCATEcompact, drop, initial sync
BackupRMAN (hot/cold backup, incremental)mongodump/mongorestore, filesystem snapshot, MongoDB Cloud Manager
Data dictionarySYS schema, DBA_* views_mdb_catalog.wt, db.serverStatus(), db.stats()
MonitoringAWR, ASH, V$ views, OEMdb.serverStatus(), profiler, MongoDB Atlas, mongostat, mongotop
Caution: Your use of any information or materials on this website is entirely at your own risk. It is provided for educational purposes only. It has been tested internally, however, we do not guarantee that it will work for you. Ensure that you run it in your test environment before using.
Thank you
Rajasekhar Amudala