ORMs don’t kill databases. Developers do.

Following a recent post I wrote Phillip Haydon made an excellent argument about not using LINQ in ORMs like nHibernate and Entity Framework without consideration to what they are doing.

Something I definitely agree with.

Just as guns don’t kill people, ORMs don’t kill databases. Developers do.

I should have picked up on this because it’s happened to me on a project I was working on.
Death by ORM
During development everything was performing well. So well that even the most sceptical developers decided to use ORMs instead of stored procedures.

The application was responsive and users were happy.

However in production there has no happy ending. The application went from running like sh!t off a proverbial shovel to just sh!t.

It was a nightmare and the finger pointing began.

The problem was we assumed (always a bad thing) the queries generated by the ORM would be as good as if we had written them ourselves.

So when we looked at what was being generated it came as a bit of a shock to see what was going on.

But while it was easy to use the ORM as a scapegoat the reality was developers were at fault.

Here’s a simple example of how even the smallest of changes can make a difference in the SQL ORMs generate.

In the code below all we want nHibernate to do is select the of the fruit that is NOT also a color.

[Test]
public void Tale_Of_Two_Queries()
{
    var fruitDatabase = new FruitDatabase();
    using (ISession session = fruitDatabase.Session)
    {
        using (ITransaction txn = session.BeginTransaction())
        {

            var apple = new Fruit() { Name = "Apple", IsAlsoAColor = false};
            var orange = new Fruit() { Name = "Orange", IsAlsoAColor = true };

            session.Save(apple);
            session.Save(orange);
            txn.Commit();
        }

        var firstQuery = session.Query<Fruit>()
        .Where(f => !f.IsAlsoAColor)
        .Select(f => f.Name)
        .ToList();        

        var secondQuery = session.Query<Fruit>()
                .Where(f => f.IsAlsoAColor == false)
                .Select(f => f.Name)
                .ToList();
    }
}

For the query that uses !f.IsAlsoAColor the SQL query looks like this

select fruit0_.Name as col_0_0_
from   Fruits fruit0_
where  not (fruit0_.IsAlsoAColor = 1)

For the query that uses f.IsAlsoAColor == false the sql generated looks like this

select fruit0_.Name as col_0_0_
from   Fruits fruit0_
where  case
         when fruit0_.IsAlsoAColor = 1 then 1
         else 0
       end = case
               when 0 /* @p0 */ = 1 then 1
               else 0
             end

While this is a trivial example it highlights the fact you don’t know what the generated SQL will be, let alone the execution plan.

And if your query returns the results you want are you really going to spend time finding out what’s going on ‘under the hood’?

How comes nobody talks about this?

I can’t ever recall a presenter warning about this during any ORM talk I’ve been to. The focus always on what it can do and how it compares to other ORMs rather than best practices.

It’s not just a .Net problem either

After talking to Ruby on Rails developers this is a problem for them too, because Active Record doesn’t work 100% of the time. When it goes wrong they have to implement workarounds to execute queries without using active record.

So how can I make sure it doesn’t happen to me?

The first thing is to know what issues to look out for. The nHibernate profiler alerts page is an excellent resource for this.

With this information you can use profiling tools to see what queries your ORM is generating and how your application is performing.

My last tip is to always use the best data access method for what you’re doing. It’s easy to become complacent or aim to everything using an ORM, but if it makes more sense to use a stored procedure then that’s what you should do.

It would be good to hear what your experiences are with issues like this and to share any tips/tools you have used to avoid ORM performance issues.

In the meantime I’ll leave you with this excellent DBA vs. Developer (Star Wars Style) video

Comments

  • John Jenkins

    I don’t use nHibernate but this post reminds me of the mess we got ourselves in.  Won’t be making that mistake again!

  • Phill

    Been in this mess with L2S, EF, and NHibernate. Tools like NHProf help avoid the problem. It’s just people write code, see it working, and think nothing more of it. :( then bad SQL gets in that could have been avoided.

  • Phill

    Been in this mess with L2S, EF, and NHibernate. Tools like NHProf help avoid the problem. It’s just people write code, see it working, and think nothing more of it. :( then bad SQL gets in that could have been avoided.

  • KTB

    The data access layer is probably the easiest part of an application. It may be a bit tedious but there are some good helper utils (like in SpringFramework for java) that take care of this.
    Anyhow, introducing ORM frameworks and writing SQL using java/.net “query builder methods” just complicates things.
    “OpenSessionInView” is the most ridiculous (anti)pattern that I know, and people seriously use it. And have problems with the session still not being there for whatever reason. So they turn lazy loading off or initialize the objects before closing the session (so no benefit for using an ORM framework).
    I have never seen an ORM framework applied so that it was obvious that it actually helped the project be more manageable. Always full of kludges and nobody knows how the thing works, and a horror to maintain for people other than those who wrote the thing.
    And all this for the easiest part of an application, reading rows from a db!

  • http://lucisferre.net Chris Nicola

    Agreed the most valuable thing you can learn about SQL as a developer is how to use and design for using an ORM properly.  Tools like nHibernate profiler are invaluable for this, don’t ORM without it.

  • http://lucisferre.net Chris Nicola

    Agreed the most valuable thing you can learn about SQL as a developer is how to use and design for using an ORM properly.  Tools like nHibernate profiler are invaluable for this, don’t ORM without it.

  • Sam De La Garza

    we use nhibernate on our team, but we’ve also used nhibernate profiler from the very beginning and until we understood the better way of writing our linq (for nhibernate) we would closely look at the sql that was generated.  Ayende has a good presentation on TekPub and he DOES go into detail about writing better queries for nhibernate.  I guess knowing this up front made the difference in the world.

    I wouldn’t avoid using an ORM in the future unless there was a real reason.

  • Sam De La Garza

    we use nhibernate on our team, but we’ve also used nhibernate profiler from the very beginning and until we understood the better way of writing our linq (for nhibernate) we would closely look at the sql that was generated.  Ayende has a good presentation on TekPub and he DOES go into detail about writing better queries for nhibernate.  I guess knowing this up front made the difference in the world.

    I wouldn’t avoid using an ORM in the future unless there was a real reason.

  • http://darwinweb.net/ Gabe da Silveira

    To ORM or not to ORM is one of the foremost religious wars of our time.  One reason is because an ORM is often the first thing that a novice will reach for because SQL seems confusing and they don’t want to understand it.  Meanwhile, the only effective way to use ORM is with a deep understanding of SQL and remaining ever vigilant over what the ORM is doing.  ”Doesn’t this defeat the purpose of ORM?” some would ask.  Absolutely not.  ORMs exist because most queries are actually quite simple, and there’s a ton of boiler plater code in mapping RDBMS data types to your application code, etc.  There is a tremendous amount to be gained even from very simple ORMs.  As they get more complex, impressive things are possible, but more things can go wrong too.  I think there’s definitely a point of diminishing returns where it’s better to just do things in a more simple and straightforward manner with fewer layers.  If an ORM makes 95% of your queries easy and painless, there’s no shame in dropping to SQL for the other 5% if it makes things clearer and more performant.

    If, on the other hand, you are using ORM to try to abstract away SQL, perhaps you should be looking a different type of database.  Even though NoSQL is touted as the new thing, it might be more efficient for a new developer to start with more basic data stores like Redis or Mongo and then graduate to SQL when they have a little more background to appreciate the flexibility and composability of the relational model.

  • http://weblogs.asp.net/thangchung thangchung

    Yes, I totally agreed with you. Some of errors caused by developer, such as messy sql generated, bad code,.. But we have NProfiler with NHibernate, SQL profiler with L2S or EF. With me, I always try to using these tools when I work on ORMs. Along with that, we have a lot of projects using store procedure for DAL as well, all of them are also work well with some boring CRUD actions. But no problems, there is according to your requirement that we will choose appropriate methods and technical for DAL. IMHO

  • http://www.facebook.com/jdpeckham James Peckham

     SQL is too confusing? LOL no… it’s because SQL is so ridiculously trivial and boring. ORMs solve the boring repetitive coding problem… not the complex/non-trivial problem.