The Future of Databases

The Story So Far

I’ve been in love with data storage since I first opened up SQL*Plus and issued a select statement. The different ways to store data are fascinating. Even within a traditional OLTP database, there are a variety of design patterns that we can use to facilitate data access. We keep coming up with different ways to solve the problems what we’re facing in business. The problem is that as the field of computer science advances, and businesses increase in complexity, the ways that we store data must become more complex as well. Exponentially scaling storage complexity isn’t something that I like to think about, but it’s a distinct possibility.

General purpose OLTP databases are not the future of data storage and retrieval. They are a single piece in the puzzle. We’ve been working with OLTP systems for well over 20 years. OLAP is a newer entry, bringing specialized analytical tricks (which are counter intuitive to the way relational data is stored) to the masses. Hell, there are a number of general purpose analytical storage engines on the market. These general purpose analytical databases integrate well with existing databases and provide a complement to the transactional specialization of OLTP systems.

That’s the key, OLTP databases are purpose built transactional databases. They’re optimized for write operations because way back in the dark ages it was far more expensive to write data to disk than it was to read from disk. Data couldn’t be cached in memory because memory was scarce. Architectural decisions were made. The way that we design our databases is specifically designed to work within this structure. A well designed, normalized, database has minimal duplication of data. In OLTP systems this also serves to minimize the number of writes to disk when a common piece of data needs to be changed. I can remember when I was a kid and the United States Postal Service changed from using three letter state abbreviations to two letter abbreviations. I have to wonder what kind of difficulties this caused for many databases…

In the 40 years since E.F. Codd’s paper was published, the programming languages that we use have changed considerably. In 1970, COBOL was still relatively new. 1971 saw the the introduction of C, 1975 brought us MS Basic. 1979, 1980, and 1983 saw Ada, Smalltalk-80, Objective-C, and C++ ushering in a wave of object oriented languages. Suddenly programmers weren’t working on singular data points, they were working with a object that contained a collection of properties. The first ANSI SQL standard was codified in 1986. 1990 gave us Windows 3 and the desktop PC became more than a blinking cursor. The web exploded in 1996, 2001, and continues to explode again in a frenzy of drop shadows, bevels, mirror effects, and Flash.

Throughout the history of computing, we’ve been primarily working with tuples of data – attributes mapped to values; rows to you and I. This model holds up well when we’re working with a entity composed of a single tuple. What happens, though, when the entity becomes more complex? The model to retrieve and modify the entity becomes more complex as well. We can’t issue a simple update statement anymore, we have to go through more complex operations to make sure that the data is kept up to date.

Examples Should Make Things Clearer

Let’s take a look at something simple: my phone bill.

In the beginning…

Long ago, a phone bill was probably stored in a relatively simple format:

  • Account Number
  • Name
  • Address
  • Past Due Amount
  • Current Amount Due
  • Due Date

This was simple and it worked. Detailed records would be kept on printed pieces of paper in a big, smelly, damp basement where they could successfully grow mold and other assorted fungi. Whenever a customer had a dispute, a clerk would have to visit the records room and pull up the customer’s information. This was a manual process that probably involved a lot of letter writing, cursing, and typewriter ribbon.

Eventually, this simple bill format would prove to be unreliable (P.S. I’m totally making this up just to illustrate a point, but I’m guessing it went something like this). In our example, there’s no way to tell when a customer paid or which customer was billed.

After some tinkering…

After a few more iterations, you probably end up with a way of storing a customer’s information and bills that looks something like this:

This is a lot more complicated from both a design perspective and an implementation perspective. One of the things that makes this implementation more difficult is that there are a number of intermediate tables to work with and these tables can become hotspots for reads as well as writes.

When you look at that design, be honest with yourself and answer this question:

How often will you view a single service history or general charge row?

Think about your answer. The fact is, you probably won’t read any of those rows on its own. You might update one if a change comes in from an external source, but otherwise all of the charges, history, etc on any given phone bill will always be read as a unit. In this particular instance, we’re always consuming a bill’s entire graph) at once. Reading a bill into memory is an onerous prospect, not to mention that summarizing phone bills in this system is a read intensive operation.

Fixing the glitch

There are a lot of ways these problems could be worked around in a traditional OLTP database. However, that’s not the point. The point is that there are problems that require actual workarounds. OLTP databases work well for many use cases, but in this case an OLTP database becomes a problem because of the high cost of reading vs writing. (Why should we read-optimize a system that was designed to be write-optimized when writes will probably account for only 10% of our activity, maybe less?)

I’ve hinted at how we fix the glitch at the beginning of this article – we look for a specialized database. In our case, we can use something called a document database. The advantage of a document database is that we’re storing an organized collection of values in the database. This collection of values is similar to a traditional tabular database – we have groups of similar data stored in named collections. The distinction comes in how the data is accessed.

When we’re saving a phone bill, we don’t have to worry about calling multiple stored procedures or a single complex procedure. There’s no need to create complex mappings between a database and our code. We create an object or object graph in the application code and save it. The software that we use to connect to our document database knows how to properly translate our fancy objects into data stored on a disk somewhere.

This solution has several upsides:

  • Related data is stored in close proximity on disk
  • Documents do not require strict structure
  • Documents may change properties without requiring complex changes to physical schema

Physical Proximity

My data is close together, so what?

In a traditional OLTP database, your data may be scattered across one or multiple disk drives. Physical drive platters will have to spin to locate the data on different parts of your storage medium. Drive read/write arms will have to move around in coordination with the spinning platters. The more complex your query, the more complex the dance your physical hardware will have to do; a simple high school slow dance turns into a tango.

In a document database, all of our data is stored together in a single record. When we want to read our bill, we just have to start reading at the beginning of the bill record and stop when we come to the end. There’s no need to seek around on the disk.

You might be worried that all of your data won’t be close together on disk. And you’d be right. However, many databases (including MongoDB) allow for the creation of secondary indexes to speed up data retrieval. The biggest question you need to ask yourself is “How will the applications be accessing the data?” In many applications we’re only acting on a single object. Even when our application isn’t acting on a single object, we can pre-aggregate the data for faster reporting and retrieval. When our application only works on a single object at a time, a document database provides distinct advantages – every time we need an object, we’ll be pulling back all of the data we need in a single read operation.

Strict Structure

Databases typically require data to be rigidly structured. A table has a fixed set of columns. The datatypes, precision, and nullability can vary from column to column, but every row will have the same layout. Trying to store wildly diverse and variable data in a fixed storage medium is difficult.

Thankfully, document databases are well-suited to storing semi-structured data – since our data is a collection of attributes, it’s very easy to add or remove new attributes and change querying strategies rapidly and in response to different data structure. Better yet, document databases let us be ignorant of how the data is stored. If we want to find all bills where the account holder’s last name is ‘Smith’ and they live in Virginia but the bill doesn’t have any county tax charges, it is very easy compared to constructing the query in a typical SQL database.

Using MongoDB our query might look like:

db.bills.find( { last_name : 'Smith' }, 
               { state : 'Virginia' }, 
               { charges : { type : 'county tax', 
                             $exists : false } } )

Compared to similar SQL:

SELECT  b.*
FROM    bills b
        JOIN accounts a ON b.account_id = a.id
        LEFT JOIN charges c ON b.id = c.bill_id
                               AND c.type = 'county tax'
WHERE   a.last_name = 'Smith' 
        AND a.state = 'Virginia'
HAVING  COUNT(c.id) = 0

And right about now, every DBA that reads this blog is going to be shaking with rage and yelling “But that SQL is perfectly clear, I don’t know how you can expect me to understand all of those curly brackets!” I don’t expect you to understand those curly brackets. Nor do I expect developers to understand SQL. The easiest way for us to develop is to use our natural paradigm. That’s why developers write code in C#, PHP, or Ruby and DBAs do their work in some dialect of SQL. MongoDB alleviates this because all the developers are doing is constructing a list of keys and values that must be matched before a document can be returned.

Changing the Schema

Changing the schema of an OLTP database can be an onerous task. You have to wait for, or schedule, down time. Modifications have to take place. Of course, the schema modifications need to take into account any actions (like triggers or replication) that may occur in the background. This alone can require significant skill and internal database engine knowledge to write. It’s not something that application developers should be expected to know. Why do I mention application developers? 99 times out of 100, they’re the ones who are working on the database, not a dedicated DBA.

Many newer, non-traditional, databases make it incredibly easy to change the schema – just start writing the new attribute. The database itself takes care of the changes and will take that into account during querying. When a query is issued for a new attribute, records without that attribute will be ignored (just like a column with a NULL value in a traditional database).

What about Analytics?

I don’t know a lot about analytical databases, in part because they require a different skill set than the one I’ve developed. I do know a few things about them, though.

Analytical databases are currently encumbered by some of the same problems as OLTP databases – data is stored in tables made up of rows and columns. Sure, these are called dimensions/facts and attributes, but the premise is the same – it’s a row-based data store.

Row-based data stores pose particular problems for analytic databases. Analytic databases throw most of the rules about normalization in the garbage and instead duplicate data willy nilly. Without joins, it’s very quick to query and aggregate data. But the problem still remains that there is a large quantity of repeated data being stored on disk.

Columnar databases attempt to solve this problem by compressing columns with similar values and using some kind of magical method to link up columnar values with their respective rows. Sounds complicated, right? Well, it probably is. Let’s say you have a table with 10,000,000,000 rows and the CalendarYear column is a CHAR(4). If there are only 25 different values for CalendarYear in the database, would you rather store 40,000,000,000 bytes of data or 100 bytes of data? I know which makes more sense to me.

Interestingly enough, there are two approaches being taken to solving this problem. The first is by creating single-purpose columnar databases. There are several vendors providing dedicated columnar databases. Other database developers are looking for ways to leverage their existing database engines and create hybrid row and columnar databases.

Looking Into the Future

There are a lot of interesting developments going on in the database world. Many of them seem to be happening outside of the big vendor, traditional database space. Most of this work is being done to solve a particular business need. These aren’t the traditional row-based OLTP systems that we’re all familiar with from the last 30 years of database development. These are new, special purpose, databases. It’s best to think of them like a sports car or even a race car – they get around the track very quickly, but they would be a poor choice for getting your groceries.

The next time you start a new project or plan a new server deployment, think about what functionality you need. Is it necessary to have full transactional support? Do you need a row-based store? How will you use the data?

Comments

16 Comments so far. Comments are closed.
  1. Great article Jeremiah, really well written and I thoroughly enjoyed it .

    I find this subject incredibly interesting and often ponder where database technology will move to next. I want to know when I can expect to be out of a job after all :-)

    You may find this conversation on Stackoverlfow to be of interest:

    http://stackoverflow.com/questions/1171321/what-do-you-think-the-future-holds-for-database-technology

  2. This was a great, great article. Everytime I come across one of these from you or Brent, it makes me want to pick up that MongoDB book at Borders that I keep eyeing everytime I go.

    • Thanks for the kind words. I’m planning some more practical articles in the near future, so you’ll get some more realistic use cases apart from that vague query that I posted.

      Why spend money on the book? Just hit up MongoDB.org and play with a copy of mongo in the browser via an interactive tutorial.

  3. antonio,

    When a read the word semistructured in an article I ask myselft: what’s semi? for example: what’s something semiboring? or what’s something semiblue?, …

    • Aren’t the vagaries of the English language entertaining? I opted for using “semi” instead of one of many longer phrases like “largely similar but different in multiple areas” or any number of contrived phrases.

      I think the color blue-green falls into a semi-blue/semi-green category.

  4. This is great article Jeremiah. Plenty of very interesting and valid observations. But as I began my career in ‘dark ages’ from C and C++, I realize that in the end something that looks like a simple search, may become a very complex beast beneath. Looking at db.bills.find: If it wasn’t bills but for example – cars – with thousands of attributes? The object – attribute relationship is something defined within structures of database. If there is thousand of attributes, scanning them in linear manner is costly. Building dictionaries over the list is building indexes, and here we come again to good practices vs bad practices, normalization (of some sort) etc.

    • Thanks for the kind words. Scanning thousands of loosely defined attributes can become incredibly onerous. At some point with MongoDB you can end up working with secondary indexes and normalization/design issues. It’s a very real prospect with any database that has any kind of schema. Different databases solve the problem differently. Oddly enough, there are some aspects of databases that don’t change, regardless of the underlying platform.

  5. John "Z-Bo" Zabroski,

    Please, do not ever design an accounting system. I have to deal with system structures like your gambit all the time. You have no idea how bad your logical design is. Why are you even giving performance advice, when your logical schema is shit?

    The fact you are arguing about reads and writes based on a logical schema shows me two things:
    (1) You don’t realize your logical schema is stupid and ugly, and any real designer will first have to correct the fact you are incorrectly storing accounting system details
    (2) You don’t understand what reads and writes in a database management system are/can be based off of

    • A couple of points:

      1) It’s pretty easy to make some solid estimates on the number of reads/writes that you can anticipate from a given logical design.
      2) I do understand what causes reads/writes in a database as I tune against this every day.
      3) Insulting people on the internet is particularly childish. Doubly so since google has indexed this page for all of eternity.

      • John "Z-Bo" Zabroski,

        No, your database design is wrong, judging by the only use case you presented. The question you pose about updating general charges is out and out crazy. Updating a general charge, according to your schema, means you are also updating the Bill. To me, a Bill has a very clear meaning: it is a “posted”/”finalized” account of what we BILLED somebody on a given DATE. If we retroactively allow updates to General Charge, then the meaning of the Bill is garbage. We have no way to do retroactive analysis on accounts. Your model is not auditable. This system cannot do reconciliation. Most accounting systems have something called a “Charge Master” which explains what charges are, when they were active, etc. They also usually have “Contracts” and “Fee Schedules” which adjust what the client actually pays (vs. what Charge Master says the service should be billed for). Such scheduling often needs to take into account government regulations, especially in multi-national situations.

        No, it is not easy to make estimates on how many logical vs. physical reads and writes an operational will have based on the logical schema. For example, if the database has triggers, then the transaction may be appended with additional writes. No, it is not easy to performance model this, because the underlying physical data store will be the foremost governor of how resources are managed under-the-hood and logical design has little to do with how long it takes to rollback a transaction that aborts, and even concurrency models like multi-version concurrency control can vary by physical data store characteristics. The underlying hardware matters, too; the quantum tunneling offered by flash memories is a big game changer, as it can dramatically reduce the time it takes to rebuild a RAID array AND can cut down on the total volume of disks you need in order to do a RAID setup (most people speak about performance, but new hardware has some compelling stories with regards to restore and database file partitioning).

        Yes, the Internet remembers almost everything. I apologize, since being more thorough the first time through would’ve been the right way to go. It is mainly pent-up venom from having to waste 20 hours a week dealing with systems with a lot of strange characteristics. I know by now that even venting does not fix these problems, since they are social in nature.

      • John – I think the one thing that you’re missing about this post is the phrase “P.S. I’m totally making this up just to illustrate a point”. This is all just a hypothetical. Were this for a production system I would make different design choices. But it’s not. That’s why there’s only a hypothetical bill schema presented and not a full blown database design.

        I’m confused why you’re persisting in saying that I’m wrong about this hypothetical. Being pissed off about something else gives you no right to vent your frustration at someone else. Calling into question someone else’s knowledge and ability in a blog post because you’re pissed off about something else is just childish.

        Finally, yes, I am totally aware of the vagaries and nuances of various and sundry storage solutions, partitioning schemes, solid state storage devices, and other types of hardware magic intended to counteract the rotational latency of a spinning platter of metal.

      • If you are making something up to prove a point, then you need a good example in order for that point to be valid. Maybe you HAVE seen an accounting system that works like your logical schema above. THEN your blog post should be about (a) we don’t have permission to re-write this trash, so what should we do? (b) how can we minimize logical schema querying & updating errors in the same way rdbmses do?

        I think you are being a bit overly defensive here (but am understanding of why). Not everyone understands how to build accounting systems. I would guess you could be an above average or great developer, since I’ve seen many above average developers and even great developers with absolutely no knowledge of how to build an accounting solution. I mainly regret making my comments earlier sound like they were about “you”. I had just read so many blogs referenced on HN or reddit lately, and all of them had similar flaws. What I dislike is people making decisions with simplified trade-off models; it usually amounts to “well, John Doe told me this works in situation X, and my problem looks a bit like situation X”. Usually, the facts are that there are so many options that any single person can only contemplate a few of them.

        In my experience, the part about SQL databases that is hardest to scale is the cost for better abstraction facilities. SQL Server Standard, for instance, is fairly limited in ways you can keep the logical schema in tact while tuning the underlying physical schema. For that, you need Enterprise edition. Oracle is the same way, b/c the salespeople know that Fortune 500 companies will pay for “proven” solutions.

  6. Dan Scott,

    Sorry to be the crumdgeon on this, but there are more reasons than simply optimizing write times that relational stores arose, IMHO. I was writing code in the days before relational. We are still seeing the impact of those disparate, siloed approaches to this day. The efficiency of storage was actually secondary to the goal of assuring that there was only one version of “truth” on file at one time. In the document data storage scenario you paint we will end up where we started. Customer information duplicated across a vast set of records that will soon get out of synch (to give one small example.) The better answer is to maintain the relational store as the underlying engine/integrity gatekeeper. Using specialized features such as materialized views, analytical engines, etc. that use these relational stores as their source will allow us to gain the advantages of both POV

    • I absolutely agree with you, Dan. A document database approach brings with it a whole slew of other problems, but it also solves certain problems.

      Ultimately, I don’t think that materialized views and OLAP solve all of our problems, nor do I think that NoSQL/document/next generation databases solve them either. Using the most appropriate tools for the job make sense. As John “Z-Bo” Zabroski points out, there’s no ability to audit in this design. Plus, you certainly wouldn’t want to use a data store with limited or no transactional control for something like financials. But there are other places where these types of data stores make sense.

      In the end: use the right tool for the job. Not everything needs a ten ton hammer.

  7. Mat,

    Just a quick note. Analytical databases by nature are not designed around the rows and columns of a table. Though dimensional, they store data in related blocks using off set addressing. The fact table model with supporting dimensions was defined as a way to model analytical databases within a relational database.

    • I knew that some analytical databases can, or do, use a relational engine in the back end. Thanks for the clarification that the ones I know of are probably anomalies in the world of analytical databases.

This site is protected with Urban Giraffe's plugin 'HTML Purified' and Edward Z. Yang's Powered by HTML Purifier. 531 items have been purified.