views:

495

answers:

3

I would like to know if there's a really performance gain between those two options :

Option 1 :

  • I do a SQL Query with a join to select all User and their Ranks.

Option 2 :

  • I do one SQL Query to select all User
  • I fetch all user and do another SQL Query to get the Ranks of this User.

In code, option two is easier to realize for me. That's only because the way I design my Persistence layer.

So, I would like to know what's the impact on performance. After what limit I should consider to take Option 1 instead of Option 2 ?

A: 

It depends upon how many users you anticipate. Option one will definitely be faster, but with a reasonable amount of data, the difference will be negligible.

Dave
Every round-trip hurts, even when there's just 10 or 20 users, you're doing a lot more work than needed
Sander Rijken
+1  A: 

If ranks are static values, consider caching them in your application.

If you need users frequently and ranks only rarely, consider lazy-loading of ranks. (e.g., separate queries, but the second query gets used only occasionally).

Use the join if you're always going to need both sets of data, and they have to be current copies of the database.

Prototype any likely choices, and run performance tests.

EDIT: Further thoughts on your persistence layer, because I'm facing this one myself. Consider adding "persistence-like" classes that handle joins as their basic query, and are read-only. Whether this fits your particular scenario is for you to decide, but a lot of database access for many apps is based on joins, which can be rather large and complex. If you can handle these in a consistent manner with your persistent, updatable objects, it can be a big win for your overall architecture. Conceptually, it's a lot like having a view in the database, and querying the view instead of writing a join, but you're doing it all in code.

Cylon Cat
Do you have some example or link about your "Persitence-like" classes ?
Melursus
Nothing I can post online, since they're not written yet! I've written entity classes, that behave much like LINQ to SQL entities, but are populated by "classic" ADO.NET code. I also have Active Record classes that encapsulate table-level queries and data access code, and that generate INSERT and UPDATE statements. The Active Record classes populate entities from DataSets. Entity classes contain metadata to support ActiveRecord function. We'll use code generators to build these in the future. The same structure should work for complex queries. Wish I could use LINQ, but I can't.
Cylon Cat
+6  A: 

Generally speaking, the DB server is always faster at joining than application code. Remember you will have to do an extra query with a network round trip for each join. However, if your first result set is small and your indexes are well tuned, this model can work fine.

If you are only doing this to re-use your ORM solution, then you may be fighting a losing battle. I have invariably found that I need read-only datasets that can only be produced with SQL, so I now use ORM for per-object CRUD operations and regular SQL for searches, reports, aggregates etc.

Mark Porter
What's you mean by round trip ? By curiosity, what ORM are you using ?
Melursus
Round trip means going from the application to the database server and back. When you're joining in the application, you're running subqueries in a loop, ie you run N extra queries/roundtrips, which scales very badly
Sander Rijken
Exactly. If your first query is always going to have a sane maximum number of rows (like, say, Super Model Chess Champions) and the child table is fast and small (like their children's names) then joining in the app doesn't have a big consequence. If the joins are large or continuously growing (all of your customers and their orders) this can get ugly in production after you have moved on to other things.
Mark Porter
We develop in Cold Fusion and Myna (http://www.mynajs.org). For CF we use a home-grown solution that generates DAO's from the table metadata, in Myna we use Myna's runtime ORM solution. In both cases, we extend the generated objects with extra functions that do more complex queries in SQL and either return structured data or arrays of DAO's from the persistence layer. For more complex objects, we composite multiple DAO's with lazy binding.
Mark Porter