Recently, I had a database for a customer that has the usual plethora of several hundred stored procedures, nicely normlized schema, and a gob of indexes and statistics to boot for optimized searching.
The customer wanted a small change to a stored procedure that would return a new field to the UI. Dutifully, I went about modifying the usual things - UI, Biz Logic Layer, Model updates, stored proc, table alter, etc. Well, after making this and about 30 other small changes in the development environment, we push to the QA server for more testing. After banging away and doing a quick performance check, everyone gives a thumbs up. So, over the weekend, we do the hotfix push to production.
So, on 8:30AM on Monday, the performance on SQL Server went totally south! Oh the horror! I mean, way south, to the point that the server was completely sluggish.

At this point, I am totally baffled. Did Windows update do something nasty? No. Is there some crazy memory issue on the server? 16GBs, 9 free. Dang. That's not it. Did SQL Server's priority get bumped down accidentally by the Admin? Nope. I'm screwed and will have to back out the build, I think.
Then I look at the process manager and see that SQL Server is just spinning wildly, using all CPU cores. But it's I/O activity shows that it is doing virtually nothing- nada. Wait. Could I have possibly screwed this up by adding just one little dinky field? In short, yes. I suspect that I have a slew of deadlocks or at least a bunch of backed up locks. So, I whip out sp_lock2 (find it here: http://support.microsoft.com/kb/255596 ).
sp_lock2 is an extended version of sp_lock. Essentially, it tells you what the heck Sql Server is doing in terms of traffic for execution requests. Here is a sample output for sp_lock2:

It turns out that the very table I modified got a 120 million row import over the weekend too. Well, that's not really that big a deal, it's basically a write / audit table for details in a complex transaction, computing profit margins, targets, and such. Not rocket science. Except, yours truly didn't realize that the stored proc using this table was being hit concurrently by 100+ users and a new SQL job!
So, the additional stress caused by the long running job surfaced the weaknesses in the stored proc. It turns out that the scan to delete the existing computations and then insert updated ones was causing a gazillion table lock requests. This effectively crippled the server. The problem was solved by adding a statistical index to the new column I added and voila! Problem solved.
Normally, you will only see a few hundred rows or even a couple of thousand requests at a time, even with a busy SQL server instance. Sp_lock2 returned the app's SPID along with a backlog of 10,000 locks in my case! By looking up the object_id(objid) returned by sp_lock, I quickly zeroed in on the offending functionality. It was the stored procedure's attempt to delete based on a missing constraint (causing a full table scan of 120+ million rows) and the lack of statistics on my secondary join on the new column. Short summary - performance was abysmal.
Without sp_lock2, it would have taken me forever to find the problem. Next time, I'll know what to do right away! This is what I like to see on a SQL Server!
