ORMs don’t kill databases. Developers do.
TweetFollowing 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.

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
- John Jenkins
- Phill
- Phill
- KTB
- http://lucisferre.net Chris Nicola
- http://lucisferre.net Chris Nicola
- Sam De La Garza
- Sam De La Garza
- http://darwinweb.net/ Gabe da Silveira
- http://weblogs.asp.net/thangchung thangchung
- http://www.facebook.com/jdpeckham James Peckham