views:

3351

answers:

4

Context

My current project is a large-ish public site (2 million pageviews per day) site running a mixture of asp classic and asp.net with a SQL Server 2005 back-end. We're heavy on reads, with occasional writes and virtually no updates/deletes. Our pages typically concern a single 'master' object with a stack of dependent (detail) objects.

I like the idea of returning all the data required for a page in a single proc (and absolutely no unnecesary data). True, this requires a dedicated proc for such pages, but some pages receive double-digit percentages of our overall site traffic so it's worth the time/maintenance hit. We typically only consume multiple-recordsets from our .net code, using System.Data.SqlClient.SqlDataReader and it's NextResult method. Oh, yeah, I'm not doing any updates/inserts in these procs either (except to table variables).

The question

SQL Server (2005) procs which return multiple recordsets are working well (in prod) for us so far but I am a little worried that multi-recordset procs are my new favourite hammer that i'm hitting every problem (nail) with. Are there any multi-recordset sql server proc gotchas I should know about? Anything that's going to make me wish I hadn't used them? Specifically anything about it affecting connection pooling, memory utilization etc.

+1  A: 

I think multi recordset stored procedures are great in some cases, and it sounds like yours maybe one of them.

The bigger (more traffic), you site gets, the more important that 'extra' bit of performance is going to matter. If you can combine 2-3-4 calls (and possibly a new connections), to the database in one, you could be cutting down your database hits by 4-6-8 million per day, which is substantial.

I use them sparingly, but when I have, I have never had a problem (except for a newbie programmer looking at the code and not 'getting it', because they don't encounter it very often).

EJB
Good to know you haven't encountered any problems with multi-resultset procs. I haven't either (yet), but then again I've never used them under this kind of load before so I wanted to be sure.
Jaysen Marais
A: 

I would recommend having invoking in one stored procedure several inner invocations of stored procedures that return 1 resultset each.

create proc foo 
as
execute foobar --returns one result

execute barfoo --returns one result

execute bar  --returns one result

That way when requirments change and you only need the 3rd and 5th result set, you have a easy way to invoke them without adding new stored procedures and regenerating your data access layer. My current app returns all reference tables (e.g. US states table) if I want them or not. Worst is when you need to get a reference table and the only access is via a stored procedure that also runs an expensive query as one of its six resultsets.

MatthewMartin
+4  A: 

Here's a few gotchas for multiple-recordset stored procs:

They make it more difficult to reuse code. If you're doing several queries, odds are you'd be able to reuse one of those queries on another page.

They make it more difficult to unit test. Every time you make a change to one of the queries, you have to test all of the results. If something changed, you have to dig through to see which query failed the unit test.

They make it more difficult to tune performance later. If another DBA comes in behind you to help performance improve, they have to do more slicing and dicing to figure out where the problems are coming from. Then, combine this with the code reuse problem - if they optimize one query, that query might be used in several different stored procs, and then they have to go fix all of them - which makes for more unit testing again.

They make error handling much more difficult. Four of the queries in the stored proc might succeed, and the fifth fails. You have to plan for that.

They can increase locking problems and incur load in TempDB. If your stored procs are designed in a way that need repeatable reads, then the more queries you stuff into a stored proc, the longer it's going to take to run, and the longer it's going to take to return those results back to your app server. That increased time means higher contention for locks, and the more SQL Server has to store in TempDB for row versioning. You mentioned that you're heavy on reads, so this particular issue shouldn't be too bad for you, but you want to be aware of it before you reuse this hammer on a write-intensive app.

Brent Ozar
Error Handling? I write code that has more than one query in it and I've never found that to be especially taxing on the trapping. Tuning? You profile, you find the slowest query that's in the process you're tuning and you tune it. How does that change if I return 1 or n resultsets? It doesn't.
About error handling - if you use MARS, you may successfully return only 4 of 5 queries to your app. The consuming app has to know how to handle it when some queries succeed and some fail. It's not an issue inside the SP, but in EVERY app that consumes the results, and that's where it gets tough.
Brent Ozar
About tuning - if you're using the same query in several SP's, and you "fix" that query during tuning, you can't just "fix" it in one place. You have to figure out every place where that query is being used, and fix them all. Better to break results queries out into separate SP's.
Brent Ozar
Some interesting points against using them generally, but not nothing that would prevent me using these procs in this specific instance. I'm deliberately sacrificing reusability for performance here (you sound like you could shed some light on whether the performance benefits are worth the effort)
Jaysen Marais
A: 

Thanks for the replies. I haven't seen anything that would make me reconsider my choice to use multi-recordset stored procedures in this specific case, but Brent Ozar's answer is probably the most useful for anyone googling this topic in the future so I'm going to accept it.

I'll keep an eye on this question, if anyone has any more multi-recordset proc war-stories or advice I'd love to hear about it.

Jaysen Marais