Storing not very volatile information in database with cache or mongodb For a new project I'm working on right now I was doubting on which database/storage system to use for specific information which does not change that often. 

We have for instance some company-profiles which will have only incidental writes to it when things like opening-hours change. On the other hand they have a lot of read-throughput; at every page load the information has to be loaded. Storing it at the filesystem as plain documents results in very much IO; Using that as a starting point I was searching for some sort of in-memory-solution.

Normally I store this information in a Postgres database, without any caching in the application-layer. I could off course add a caching layer in redis or memcached to produce lesser IO reads from disk, and handle updates of the cache at the application-layer on update of the information

An other solution is to use MongoDB to store the 'documents'. But I don't know how mongodb handles the read/writes. Eg with every retrieval of the document does it check the filesystem, or does it serve the document from cache/RAM? (I read somewhere mongodb keeps a lot of RAM available for itself)

Can someone shed some light on this?
The answer as always is: it depends ;)

With a bit of simplification: Indexes and recently read (and written) documents are kept in RAM until that RAM is needed for something else. So wether your data is read from RAM or from file pretty much depends wether RAM on the MongoDb node(s) is sufficient to keep the index and at least part of your data (called the working set) in RAM. It is safe to say that the only thing that can replace having sufficient RAM in a MongoDB installation is to have more RAM.

So the question is: how much is sufficient RAM? And the answer again is: it depends. On the size of your database, the number of documents in it's collections, the number of indices you need. It is by no means easy to figure out the right values and that is very dependent on the situation, but I will try to give you some rules of thumb.


Whenever possible, use SSDs. Rather take half the amount of RAM and SSDs than double the amount of RAM and HDDs.
Generate a reasonable fraction of your expected data size (or use a reasonable fraction of it if you already have data). The values can be completely random, though their size should be somewhat realistic (you rarely have company names 255 characters long, for example)
Create the indices as you expect to need them. Rule of thumb: generate an index for every field or combination of fields you expect to query for. Keep in mind that a field in an compound index will be used if you query for that field alone. You really need to put some effort in this step.
Sum up the index sizes. 
If your combined index size for the test data exceeds your physical RAM, put some more into the machine, at least 1.5 times the value of your combined index sizes.
Run your performance tests.


While this sounds a bit complicated, it may save you from developing (and maintaining!) a whole layer in your application. This easily sums up over time.



Note for general scaling: Calculate the index sizes for your expected data set. Multiply that value by 1.5 at least. I'd rather suggest multiplying by >3. Take this as your memory size. The factor is actually determined by your growth factor and limited by the sweet spot where your hardware delivers the most bang for the buck. If your RAM requirements are exceeding the RAM of your hardware sweet spot, you should shard your cluster right away.