So it's now apparent to me that developers stop thinking about SQL once you abstract the database into a layer of code (such as a DAL and O/RM entities).
When you start looking at individual data entities, it's so nice to be able to reference them in code with a little bit of Customer cust = new Customer() type magic. The hidden danger though is that you rely on that for everything and stop thinking at the database level.
This is oversight more than anything and probably the job of the architect or senior guy to enforce, but when you're not looking it's easy for a developer to say, create a "data view" class that consolidates a bunch of data from joined tables into one type for displaying on say, a data grid, or a summary panel, or some such UI type entity. At the surface it makes a lot of sense, and is good design, but if the guts are such that for each base entity you pull 15 other related objects to fill in the various interface elements...and then you pull a list of 100 of those to go on a grid, and then you have several hundred users hitting it...you're in the tens of thousands of database hits per second business before you know it.
Lots of ways to accomplish this better...the one I'm refactoring to right now is offloading all that joining to a database level View and then populating the dataview class straight off the view. I'm finding good places to use this technique to speed up searches as well (I've already reduced a 2 minute account search to 2ish seconds (very wide search mind you)). The moral of the story though is that if you give developers a cool tool like an O/RM layer, they're gonna use it, and you have to police that to make sure system design is staying in line.
Reminder to me and every other dev lead out there...just because something is functional doesn't mean it's right, and don't forget to look under the hood and make sure the engine isn't wired up all funky.