views:

51

answers:

2

I have an sproc in SQL Server 2008. It basically builds a string, and then runs the query using EXEC():

SELECT * FROM [dbo].[StaffRequestExtInfo] WITH(nolock,readuncommitted)
WHERE [NoteDt] < @EndDt 
AND [NoteTypeCode] = @RequestTypeO 
AND ([FNoteDt] >= @StartDt AND [FNoteDt] <= @EndDt) 
AND [FStaffID] = @StaffID 
AND [FNoteTypeCode]<>@RequestTypeC 
ORDER BY [LocName] ASC,[NoteID] ASC,[CNoteDt] ASC

All but @RequestTypeO and @RequestTypeF are passed in as sproc parameters. The other two are built from a parameter into local variables. Normally, the query runs under one second. However, for one particular value of @StaffID, the execution plan is different and about 30x slower. In either case, the amount of data returned is generally the same, but execution time goes way up.

I tried to recompile the sproc. I also tried to "copy" @StaffID into a local @LocalStaffID. Neither approach made any difference.

Any ideas?

UPDATE: Tried to drop specific plans using:

DECLARE @ph VARBINARY(64), @pt VARCHAR(128), @sql VARCHAR(1024)

DECLARE cur CURSOR FAST_FORWARD FOR
  SELECT p.plan_handle
  FROM sys.[dm_exec_cached_plans] p
  CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) t
  WHERE t.text LIKE N'%cms_selectStaffRequests%'

OPEN cur
FETCH NEXT FROM cur INTO @ph

WHILE @@FETCH_STATUS = 0
BEGIN
  SELECT @pt = master.dbo.fn_varbintohexstr(@ph)
  PRINT 'DBCC FREEPROCCACHE(' + @pt + ')'
  SET @sql = 'DBCC FREEPROCCACHE(' + @pt + ')'
  EXEC(@sql)
  FETCH NEXT FROM cur INTO @ph
END

CLOSE cur
DEALLOCATE cur

Either the wrong plans were dropped, or the same plans ended up being recreated, but it had no effect.

A: 

Check the distribution/frequency/cardinality of the values in column FStaffID, and review your indexes. It may be that you have one staff member doing 50% of the work (probably the DBA :) and that may change how the optimizer chooses which indexes to use and how the data is read.

Alternatively, the execution plan generated by the dynamic code may be being saved and re-used, resulting in a poorly performing query (like HLGEM says). I'm not up on the details, but SQL 2008 has more ways to confuse you while doing this than its predecessors.

Philip Kelley
Actually, if anything, the slower query has less data than the others.
alphadogg
Is there a way to find which plans are being used by an sproc, if they are exclusive to that sproc, and to drop them?
alphadogg
DBCC FREEPROCCACHE will drop *all* execution plans currently stored in memory. I don't believe there's a way to pick-and-choose what gets dropped from that cache. Identifying what plan is used or owned by what query is very hard, and perhaps not possible--been a long time since I've tried.
Philip Kelley
Well, I did patch together a way to drop specific plans, and I used to drop anything that had the sproc name or that had the single view used in the coposed sql string. But, it had no effect on the issue. Seems like SQL Server insists on using a bad plan with one specific value for @StaffID.
alphadogg
What did you use to drop the specific plan? Also, I think there are hints that say "use this plan once and do not cache it", though I don't know if they can be applied to dynamic SQL.
Philip Kelley
A: 

Doing an UPDATE STATISTICS ... WITH FULLSCAN on the main base table in the query resulted in the "slow" value not being associated with a slow plan.

alphadogg