Question

When a SQL Server index is dropped (say it's a duplicate) what are the steps undertaken by the engine to clear and then rebuild the execution plans that reference it? In particular I'm wondering whether it's an all-at-once process, an as-new-queries-occur process or something in between. Thanks.

Was it helpful?

Solution

Welcome to DBA.StackExchange, and interesting question!...one I've never thought of before. I had to double check myself on what I thought the process was, so I think this StackOverflow Answer should be what you're looking for. Specifically the first statement of the answer:

Dropping/Rebuilding an Index will result in invalidation of any cached execution plans using this table/Indexed view. And sql server will generate a new execution plan on next execution.

Essentially, the plans in the plan cache will automatically be marked as invalid of any existing execution plans that reference the dropped index. Then the next time a query runs that involves the entity of which the index was dropped from, a new execution plan is automatically generated and cached in the plan cache because the old one is invalidated. (Eventually the invalidated plans are flushed from the plan cache to make room for new plans being cached.)

Here's an additional resource that concurs this is how it occurs: Dropping unnecessary indexes - effect on query plans in SQL Server 2005

OTHER TIPS

To go a bit more into details, the plan isn't flushed when the index is dropped. See repro below.

The plan stay in cache, but it is now invalid. Next time that plan is up for usage, SQL Server check whether it is valid. If for instance a schema change was made (as in dropping an index), it isn't valid. So a new plan will be generated.

Dropping the plan when an index is dropped would require meta-data which AFAIK isn't available. SQL Server would have to have in-memory meta-data for every plan cache regarding which objects they depends on. Or the plan would have to be searched for every meta-data change (like DROP INDEX) to see what plans that could be invalid. The pragmatic approach is to check at usage time if the plan has to be re-compiled, and this is the SQL Server approach (at least according to my repro below).

I recall, some 3 decades ago, when sp_recompile was introduced in the product. Before that, we wrote our own, and we just bumped the schema_ver column in the sysobjects system table (and handling overflow since it was a tinyint). Then came sp_recompile with the product which did just exactly that.

Move forward 3 decades and the product has evolved, including one total re-write (between 6.5 and 7.0) and another total re-write of the meta-data (2000 to 2005), but the same basic principals is obviously in place.

Note that sp_recompile does seem to actively flush an object from cache (if you read the source code). It doesn't seem to happen for a table, though (see the demo), but probably for a code module.

USE Adventureworks

DROP INDEX IF EXISTS x ON Sales.SalesOrderDetail

CREATE INDEX x ON Sales.SalesOrderDetail(OrderQty)
DBCC FREEPROCCACHE
GO

SELECT SUM(UnitPrice) FROM Sales.SalesOrderDetail WHERE OrderQty = 34
GO

SELECT qs.creation_time, sql.text
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text (qs.plan_handle) AS sql
WHERE sql.text LIKE '
SELECT SUM(UnitPrice) FROM Sales.SalesOrderDetail%'
GO

WAITFOR DELAY '00:00:00.5'

DROP INDEX IF EXISTS x ON Sales.SalesOrderDetail
GO
WAITFOR DELAY '00:00:00.5'

SELECT qs.creation_time, sql.text
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text (qs.plan_handle) AS sql
WHERE sql.text LIKE '
SELECT SUM(UnitPrice) FROM Sales.SalesOrderDetail%'
GO
--Note same creation_time for the plan for the two above SELECTS. The same.

--Below will produce a new plan, though
GO

SELECT SUM(UnitPrice) FROM Sales.SalesOrderDetail WHERE OrderQty = 34
GO

SELECT qs.creation_time, sql.text
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text (qs.plan_handle) AS sql
WHERE sql.text LIKE '
SELECT SUM(UnitPrice) FROM Sales.SalesOrderDetail%'
GO

EXEC sp_recompile 'Sales.SalesOrderDetail'
GO

SELECT qs.creation_time, sql.text
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text (qs.plan_handle) AS sql
WHERE sql.text LIKE '
SELECT SUM(UnitPrice) FROM Sales.SalesOrderDetail%'
GO
--sp_recompile doesn't avticely remove plan from cache, at least not for a table
Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top