Where MongoDB fits: performance and optimization

Lecture



By now you should have a good enough understanding of MongoDB to see where it might fit into your existing system. There are so many new, competing data storage technologies that it's easy to get lost trying to decide which one to use.

For me, the biggest lesson — one that, incidentally, has nothing to do with MongoDB — was that you don't have to rely on a single solution for working with data. Naturally, a single solution has obvious advantages, and for many, if not most, projects that's the sensible approach. The point isn't that you must use different technologies, but rather that you can. Only you know whether the benefits of adopting a new solution outweigh the possible costs.
With that said, I hope what you've seen so far has let you think of MongoDB as a general-purpose solution. It's been mentioned a couple of times that document-oriented databases have a lot in common with relational ones. So, to cut to the chase, let me just say that MongoDB can be regarded as a direct alternative to relational databases. Whereas Lucene can be thought of as an extension of relational databases with a full-text index, and Redis as a persistent key-value store, MongoDB is a central repository for your data.
Notice that I'm not calling MongoDB a replacement for relational databases — it's more of an alternative. It's a tool that can do much of what plenty of others can do. Some things better, some things worse. We'll look at this in more detail shortly.
Where MongoDB fits: performance and optimization

Schemalessness

A frequently touted advantage of document-oriented databases is that they're schemaless. This makes them far more flexible than traditional relational databases. I agree that being schemaless is good, but not as the main advantage many people claim it to be.

Schemalessness is often seen as license for chaotic data organization. There are domains and data sets that really are very hard to model in terms of a conventional relational database, but I see those more as edge cases. Schemalessness is tempting, but most data should be well-structured. Sure, it can sometimes be convenient, especially for adding new functionality, but in practice that can just as easily be solved by adding new optional fields.

For me, the real advantage of a schemaless architecture is the lack of setup and the minimal mismatch with OOP. This is especially noticeable when working with statically typed languages. I've worked with MongoDB in both C# and Ruby — the difference is striking. Ruby's dynamism and the popular ActiveRecord implementation already substantially narrow the object-relational impedance mismatch (object-relational impedance mismatch). That doesn't mean MongoDB is a poor fit for Ruby — quite the opposite. Rather, I think most Ruby developers see MongoDB as a modest improvement, while developers writing in C# or Java see a gulf separating MongoDB from their usual approach to manipulating data.
Think about it from a driver author's perspective. Need to save an object? Serialize it to JSON (actually to BSON, but that's nearly the same thing) and send it to MongoDB. There's no property or type mapping at all. That simplicity should definitely appeal to you as an end developer.

Writing

An area MongoDB is especially well suited for is logging. There are two aspects of MongoDB that make writes fast. First, you can issue a write command and move on without waiting for it to return or for the write to actually complete. Second, with the journaling introduced in version 1.8 and some improvements made in version 2.0, it became possible to control write behavior with respect to data durability. These settings, along with how many servers must receive your data before a write is considered successful, are configurable on a per-write basis, giving you a great deal of control over how your writes are performed and how durable they are.

Besides the performance factors mentioned, a flexible data structure can also turn out to be useful for logging. Finally, MongoDB has a concept called a capped collection (capped collection). So far we've only created ordinary collections. We can create a capped collection using the db.createCollection command, by setting the capped flag:
 //limit the collection size to 1 megabyte 
db.createCollection('logs', {capped: true, size: 1018576})

Once our capped collection reaches a size of 1 megabyte, the oldest documents start being removed automatically. You can also set not a collection size but a maximum number of documents, using the max option. Capped collections have a number of interesting properties. For example, you can modify a document, but it can't grow in size. Insertion order is also preserved, so there's no need to add an extra field for chronological sorting.

It's also worth noting that if you need to find out whether your write caused any errors (as in the case already mentioned, where we don't wait for it to finish), you can simply run the following command: db.getLastError(). Most drivers wrap this functionality as a safe write — for example, you can pass {:safe => true} as the second parameter to the insert method.

Durability

Before version 1.8, MongoDB didn't guarantee data durability on a single server. So a server failure could lead to data loss. The solution was always to run MongoDB across several servers (MongoDB supports replication). One of the most important features added in MongoDB 1.8 was journaling. To enable it, add journal=true to the mongodb.config file we created when we first set up MongoDB (and restart the server for the changes to take effect). You'll most likely want journaling enabled (in future releases it will be on by default). Despite the slight performance gain you can get by disabling journaling, doing so carries a certain risk. (On the other hand, some applications can tolerate losing a bit of data.)

Durability is brought up here because a lot of effort has gone into achieving it on a single server. Sooner or later you'll come across mentions on Google of Mongo being unreliable as a data store. However, that information is now outdated.

Full-Text Search

I hope full-text search makes it into MongoDB in a future release. With array support, basic full-text search would be quite simple to implement. For serious applications you'll most likely need to use something like Lucene or Solr. Of course, the same is true for relational databases.

Transactions

MongoDB doesn't support transactions. There are two alternatives: one is elegant but limited in its use, and the other is cumbersome but flexible.

The first alternative is the set of atomic operations. They're great as long as they solve your problem. We've already seen some of these, such as $inc and $set. There are also commands like findAndModify, which can update or delete a document and return it automatically.

The second alternative — for when atomic operations aren't enough — is the two-phase commit. Compared to transactions, a two-phase commit is roughly like manually stitching together queries compared to using JOINs. It's a storage-independent solution that you implement in code. Two-phase commits are also fairly common in the relational world when you need to guarantee transactions across multiple databases. The MongoDB site has an example illustrating the most common scenario (transferring funds). The general idea is that you store the transaction's state inside the document being updated and walk through the init-pending-commit/rollback steps manually.
MongoDB's support for embedded documents and its schemaless architecture make two-phase commits less intimidating, but it's still a complex process, especially for anyone facing it for the first time.

Data Processing

For most data-processing tasks, MongoDB uses MapReduce. There are, of course, some basic aggregate functions, but for anything serious you'll need MapReduce. We'll look at MapReduce in more detail in the next chapter. For now, you can think of it as a very powerful, more flexible alternative to group by (which, admittedly, understates what it can do). One advantage of MapReduce is that it can run in parallel when working with large volumes of data. However, MongoDB's implementation is based on JavaScript, which is itself single-threaded. What follows from that? For processing large amounts of data, you'll most likely need to rely on something else, such as Hadoop. Fortunately, these two systems complement each other so well that a MongoDB adapter for Hadoop exists.

Of course, parallelizing data processing isn't the only clear-cut area where relational databases have the edge. Future releases of MongoDB are planned to improve handling of huge data volumes.

Geospatial Data

One especially powerful MongoDB feature is its support for geospatial indexes. This lets you store x and y coordinates on documents and then find documents near ($near) given coordinates, or within ($within) a rectangle or a circle. It's easier to grasp visually, so I recommend watching the five-minute walkthrough of MongoDB's geospatial features if you want to dig deeper.

Tooling and Maturity

You probably already know that MongoDB is considerably younger than most relational databases. That's definitely something to take into account. How much it matters depends on your requirements and how you implement them. You can't ignore the fact that MongoDB is a young technology, and the available tooling isn't yet very diverse (though tooling for mature relational databases can sometimes be pretty awful too). For example, the lack of support for floating-point decimal numbers will obviously be a problem (though not necessarily an insurmountable one) for systems dealing with money.

There are upsides too: good drivers exist for most languages, the protocol is modern and simple, and development is moving along quite fast. MongoDB runs on production servers at many companies, so concerns about the technology's maturity will soon be a thing of the past.

The point of this chapter is that MongoDB is, in most cases, capable of replacing a relational database. It's much simpler and easier to understand; it's faster and places fewer constraints on application developers. The lack of transactions can be a serious and legitimate concern. But when people ask where does MongoDB fit in the ecosystem of modern storage engines?, the answer is simple: squarely in the middle.

See Also

  • [[b8218]]
  • [[b9900]]
  • [[b9901]]
  • [[b9902]]
  • [[b9903]]
  • [[b9904]]
  • [[b9905]]
  • [[b9906]]
  • [[b9907]]

See also

Comments

To leave a comment

If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Lectures and tutorial on "Databases -MongoDB"

Terms: Databases -MongoDB