2

I have 2 indexes that have the same key, but one also has INCLUDE columns. Which one can I drop?

They are the same, except IndexInclude has 6 INCLUDE columns.

Both have some reads (IndexNoInclude has much higher seeks).

I believe the IndexInclude will satisfy anything that would've used IndexNoInclude right? Since the keys are exactly the same.

Thanks for all the help in advance.

Output from sp_Blitz. Sorry for the bad format

Details: db_schema.table.index(indexid) 
Definition: [Property] ColumnName {datatype maxbytes} Secret Columns Fillfactor Usage Stats Op Stats Size
IndexINCLUDE [1 KEY] EXECUTION_TIME {datetime 8} [6 INCLUDES] 
Reads: 101,913 (101,913 seek) Writes:2,381,661,369 
0 singleton lookups; 225 scans/seeks; 0 deletes; 0 updates; 263,358,683 rows; 5.4GB
IndexNoInclude [1 KEY] EXECUTION_TIME {datetime 8} 
Reads: 1,181,595 (1,181,595 seek) Writes:2,380,483,678 
0 singleton lookups; 15 scans/seeks; 0 deletes; 0 updates; 263,358,683 rows; 2.9GB
Michael Green
25.3k13 gold badges54 silver badges100 bronze badges
asked Oct 30, 2018 at 3:22
1
  • 1
    I think you answered yourself here. Keep the index that's more useful (more reads) :). Test if the query plans that use the Include index change to OK plans, not extremely bad ones, as they will probably switch to Key Lookups. If the new plans are acceptable in performance then I see no reason to keep the Include index. Use sp_blitzIndex from Brent's gang to see more info regarding your indexes. Commented Oct 31, 2018 at 8:35

2 Answers 2

0

I believe the IndexInclude will satisfy anything that would've used IndexNoInclude right? since the Keys are exactly the same

Are they the same? Maybe I am misreading the output, but it certainly looks like IndexNoInclude has an extra key column: [ID] NUMERIC.

You should review your queries to see which of the 6 INCLUDE columns are actually being referenced / used. You could likely get away with "merging" the two indexes such that the remaining index has both key columns and between 1 and 6 of the INCLUDE columns.

answered Oct 31, 2018 at 13:57
1
  • Sorry it was my typo. [ID] is the secret column for both and I've removed it. both have same key on [EXECUTION_TIME] only. 1 has no include, 1 has 6 included columns Commented Nov 1, 2018 at 3:42
0

After reviewing the query plans using the IndexInclude, I've confirmed they don't use the 6 Included columns really (mostly SELECTs), so I've disabled the IndexInclude.

So far so good while I continue to monitor

These are the queries I used to find them (source from SQLSkills and Kendra) https://www.sqlskills.com/blogs/jonathan/finding-what-queries-in-the-plan-cache-use-a-specific-index/ https://littlekendra.com/2017/01/24/how-to-find-queries-using-an-index-and-queries-using-index-hints/

I combined the two and modified to get what I need (see actual text/query, execution count, reads/writes, last execution time)

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 
DECLARE @IndexName AS NVARCHAR(128) = 'IndexInclude';
-- Make sure the name passed is appropriately quoted 
IF (LEFT(@IndexName, 1) <> '[' AND RIGHT(@IndexName, 1) <> ']') SET @IndexName = QUOTENAME(@IndexName); 
--Handle the case where the left or right was quoted manually but not the opposite side 
IF LEFT(@IndexName, 1) <> '[' SET @IndexName = '['+@IndexName; 
IF RIGHT(@IndexName, 1) <> ']' SET @IndexName = @IndexName + ']';
-- Dig into the plan cache and find all plans using this index 
;WITH XMLNAMESPACES 
 (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan') 
SELECT 
stmt.value('(@StatementText)[1]', 'varchar(max)') AS SQL_Text, 
--obj.value('(@Database)[1]', 'varchar(128)') AS DatabaseName, obj.value('(@Schema)[1]', 'varchar(128)') AS SchemaName, obj.value('(@Table)[1]', 'varchar(128)') AS TableName, 
--obj.value('(@Index)[1]', 'varchar(128)') AS IndexName, obj.value('(@IndexKind)[1]', 'varchar(128)') AS IndexKind, 
--cp.plan_handle, 
qp.query_plan,
cp.usecounts AS execution_count
,
 querystats.execution_count,
 querystats.total_logical_reads,
 querystats.total_logical_writes,
 querystats.creation_time,
 querystats.last_execution_time
FROM sys.dm_exec_cached_plans AS cp 
CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp 
CROSS APPLY query_plan.nodes('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS batch(stmt) 
CROSS APPLY stmt.nodes('.//IndexScan/Object[@Index=sql:variable("@IndexName")]') AS idx(obj) 
--added by Jerry to get the time
INNER JOIN sys.dm_exec_query_stats querystats WITH (NOLOCK) ON querystats.plan_handle = cp.plan_handle
ORDER BY querystats.last_execution_time DESC
OPTION(MAXDOP 1, RECOMPILE);
answered Nov 1, 2018 at 9:01

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.