BrentOzarULTD / SQL-Server-First-Responder-Kit

sp_Blitz, sp_BlitzCache, sp_BlitzFirst, sp_BlitzIndex, and other SQL Server scripts for health checks and performance tuning.

Home Page:http://FirstResponderKit.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

sp_BlitzCache @SlowlySearchPlansFor not producing reliable results when looking for missing indexes

BrentOzar opened this issue · comments

Version of the script
SELECT @Version = '7.9', @VersionDate = '20191024';

What is the current behavior?
If I search for the exact plans producing a missing index recommendation, I'm not getting them. Logging where I'm at so far in the troubleshooting process:

DBCC FREEPROCCACHE;
GO
SELECT Id FROM dbo.Users WHERE DisplayName = 'Brent Ozar';
GO 5

/* The missing index hint in the plan will look like this: */
<MissingIndex Database="[StackOverflow]" Schema="[dbo]" Table="[Users]">
                  <ColumnGroup Usage="EQUALITY">
                    <Column Name="[DisplayName]" ColumnId="5" />



/* This search produces results: */
sp_BlitzCache @SlowlySearchPlansFor = '<MissingIndex Database="[StackOverflow]" Schema="[dbo]" Table="[Users]">%<ColumnGroup Usage="EQUALITY">%<Column Name="[DisplayName]" ColumnId="5"', @Debug = 1
GO

/* But as soon as you add the space after the ColumnId number, it doesn't: */
sp_BlitzCache @SlowlySearchPlansFor = '<MissingIndex Database="[StackOverflow]" Schema="[dbo]" Table="[Users]">%<ColumnGroup Usage="EQUALITY">%<Column Name="[DisplayName]" ColumnId="5" ', @Debug = 1
GO



/* It doesn't appear to be a search string length problem either - here, I'm using a different column & length: */
DBCC FREEPROCCACHE;
GO
SELECT Id FROM dbo.Users WHERE Location = 'Brent Ozar';
GO 5

/* The missing index hint in the plan will look like this: */
<MissingIndex Database="[StackOverflow]" Schema="[dbo]" Table="[Users]">
                  <ColumnGroup Usage="EQUALITY">
                    <Column Name="[Location]" ColumnId="9" />



/* This search produces results: */
sp_BlitzCache @SlowlySearchPlansFor = '<MissingIndex Database="[StackOverflow]" Schema="[dbo]" Table="[Users]">%<ColumnGroup Usage="EQUALITY">%<Column Name="[Location]" ColumnId="9"', @Debug = 1
GO

/* But as soon as you add the space after the ColumnId number, it doesn't: */
sp_BlitzCache @SlowlySearchPlansFor = '<MissingIndex Database="[StackOverflow]" Schema="[dbo]" Table="[Users]">%<ColumnGroup Usage="EQUALITY">%<Column Name="[Location]" ColumnId="9" ', @Debug = 1
GO

Hey Brent, I think I might have some info here. Looks like casting the XML as NVARCHAR(MAX) removes the trailing space. Why? Well I haven't figured that part out. It's pretty easy to repro though:

select deqp.query_plan, CAST(deqp.query_plan AS NVARCHAR(MAX)) 
from sys.dm_exec_query_stats deqs
cross apply sys.dm_exec_query_plan(deqs.plan_handle) deqp
where CAST(deqp.query_plan AS NVARCHAR(MAX)) like N'%MissingIndex%'

I pulled out a random row with a Missing Index and the results look like this:

Original (XML) column:
<ColumnGroup Usage="INCLUDE"><Column Name="[parameter_id]" ColumnId="1" />

CAST as NVARCHAR(MAX):
<ColumnGroup Usage="INCLUDE"><Column Name="[parameter_id]" ColumnId="1"/>

Note the space is in the XML result only. The second one that is cast as NVARCHAR has no space.

I'm not sure how to address it, but this looks like the problem.

After much experimentation, I don't think there is a way to avoid the conversion to NVARCHAR causing the space to disappear.
One idea that might solve this issue is to use REPLACE(@body_where, N' %',N'%'). What side effects might this have? It certainly solves your use case.

Ouch. Yeah, this is tough: if we strip out the spaces, we're going to false-positive on too many things. Closing.