Preparing to Upgrade SQL Server: Finding Deprecated Features with DMVs and Extended Events

Comments 0

Share to social media

Preparing to upgrade SQL Server is part automation, part detective work. The automated part (running the Database Migration Assistant or Azure Migrate against existing databases) catches most compatibility issues, but it doesn’t always tell you WHERE in your application code a deprecated feature is being used – only that it’s being used somewhere. This article shows two DMV and Extended Events techniques for pinpointing the specific queries and applications using features that will break in future SQL Server versions. What we’ll cover: (1) query sys.dm_os_performance_counters for deprecation-related counters to identify which deprecated features are being exercised on the instance; (2) create an Extended Events session capturing sqlserver.deprecation_announcement and sqlserver.deprecation_final_support events to record every execution along with the SQL text, session ID, database, and client application – giving you the pinpoint data to fix the code before the upgrade. The techniques complement the Migration Assistant’s static analysis with runtime evidence from production workloads.

Getting started

The job of preparing to upgrade SQL Server is one that DBAs look forward to but also dread in equal measure; on the one hand there is the delighted anticipation of new shiny things to work with, on the other hand the dread of knowing what to do if everything breaks or making sure that everything is ready for the changes? The problem is that your databases may be using features that don’t work in the version of SQL Server you’re upgrading to. If so, then they’ve got to be altered to get everything to work. Only if you make sure that all the databases will work on the new version of SQL Server can you look forward to a stress-free upgrade.

SQL Server makes things as easy as possible for you with various tools and features that let you know what if anything will cause problems and therefore stop working if you upgrade, and they will also warn you what features are likely to be problems in a version or two. There is the upgrade advisor tool, a dedicated application that will analyse all the components of SQL Server that you have installed and produce reports for you to review to guide you through an upgrade. This isn’t what we are going to look at, but I wholly recommend that you take a look at the Upgrade Advisor for the SQL Server version you intend to install, even if you are not intending to upgrade yet, and review what might be a problem and what information you will get out of it. Just so that you are one step ahead when the upgrade *does* get started. The SQL Server Upgrade Advisor can be found here: A wise DBA will give developers as much warning as possible about the work involved in migrating a database application to a new version. Project Managers don’t like surprises. By making future-proofing part of the development culture, we can avoid all that last-minute scrabbling with code at the point at which the upgrade is due. In this document, we’re going to assume that you are familiar with the upgrade advisor, and so are going to look at ways that we can gain the detailed information simply by using information captured automatically in SQL Server and, show how to use that to inform development and the design team to be ready for new versions of SQL Server well before the time of doing the server upgrades. No doubt you have heard all about the good things that are found in SQL Server system DMVs (Database Management Views) and we can get started with some information from the dm_os_performance_counters DMV. 1820-7016cd28-994e-402d-ac03-f66e80baee7 So we have here a convenient way to look at the activity going on within our SQL instance that is using features that are destined to be removed from SQL Server in future versions. Let’s see what sort of information it can give us; 1820-ce9c9294-7f60-4a1b-a8f3-f106da70829 So, on my laptop instance we have a few different deprecated features being used. I’m not sure what the language-related items are so I might investigate those at another time. The deprecated features listed that would give me concern on a production system are Deprecated encryption algorithm , ‘::’ function calling syntax, sysdatabases , sysservers , syscolumns , XP_API and More than two-part column name. For a full list of deprecated features in SQL Server 2008 and their descriptions take a look at http://msdn.microsoft.com/en-gb/library/bb510662(v=sql.100).aspx. On our production servers we chose to review “More than two-part column name“ first. This feature is described as “A query used a 3-part or 4-part name in the column list. Change the query to use the standard-compliant 2-part names. Occurs once per compilation.” So we are seeing an application accessing our databases in some way that is using TSQL that will cause an error in a future version of SQL Server. It’s going to be useful to our development division to know about this as soon as possible so that they can work on refactoring the code in good time. As you can see though, the dm_os_performance_counters DMV only keeps a record of each time a feature is used, not where, when or how it was executed. We need some other way to collect executions. Let’s take a look at creating an Extended Events(XE) session to capture the information we need. The events we are interested in are sqlserver.deprecation_announcement and sqlserver.deprecation_final_support. The distinction between these two events is that features in the former are due to be removed from SQL Server within 3 versions whereas those in the latter will not be available in the next version. Clearly features in deprecation_final_support are those that will demand your immediate attention and could potentially prevent an upgrade until the causes are resolved. To create the XE session on SQL Server 2008 + SQL Server 2008 R2 we need to execute some TSQL; (Note – if you want to create this session on SQL Server 2012 there is a slight change in the name of the file system target. You need to use What is this code doing? Let’s review it section by section:
  • CREATE SESSION – well this creates the session! Give it a name (your choice) and scope (Server or Database)
  • ADD EVENT – the events that you want to capture need to be added to the session. Not sure which ones to use? Check out the results from
  • ACTION – What information should be collected when the event gets fired. Not sure what information you can collect? Check out the results from
Right, with the XE session created it I started it running and left it for 24 hours. I was somewhat surprised when I came to review the output – I had 1GB of xel files with almost 1M events recorded. Significantly more than I was expecting. Once I had brewed a fresh pot of coffee I set about getting some summary information from all of this data – there was no way it would give me a lot of information I could take action on, I would need to re-run the session with some filtering in place. There are (always?) a couple of ways to review the data collected by an XE session. We can use [sys].[server_event_sessions], [sys].[dm_xe_sessions]and [sys].[dm_xe_session_targets] to access the data directly: However, don’t expect details very quickly if you have a lot of data as I did, because the performance will suck: Terribly. It’s also tricky to read through XML results. We need to shred the XML into something easier to work with. I decided to import the data into a database on a different server so that I could analyse and re-analyse it without compromising my production systems and without the burden of reading XML. Once the files were zipped, copied to the different server and then extracted, I used fn_xe_file_target_read_file to access the XEL files. It’s a pretty simple function that takes 4 parameters – path, mdpath, initial_file_name, initial_offset. path is simply needs the UNC of the XEL file(s), mdpath needs the location of the XEM file that the XE session creates, initial_file_name needs to have the name of the first XEL file if you don’t want to read them all, initial_offset needs the location in the file to start reading. For my purposed I only needed to specify the first two parameters and then NULL for the final two. This isn’t much better than previous query, let’s add the code to shred the XML and then insert it into a database table. Notice that I also imported the xml value in its entirety (the column [v].[xml_data]), this means I can quickly shred more information out of the data if I have missed something without having to re-access the xel files. So here we have it, a database table full of XE data that is using features that are about to exit the SQL Server world. Not so fast, query the XE_Deprecated_Events table for values and you will very likely see ‘SQL_Text Unable to retrieve SQL text’ in lots of places. Where code is executed within a database object it is possible that the SQL Text is not collected. Needless to say, I was pretty disappointed. We could still get good information from the data; things like which applications were using which deprecated features, which were the worst offenders, which features are on final Support and need urgent attention etc etc but we can’t actually make the final step to get to the line of offending code in some very important cases. Back to the XE Drawing Board, we need to capture more information. Now, the old fashioned way of getting this information would be SQL Profiler and in that you would look for SP:Completed events, in XE the equivalent is sqlserver.module_end. Adding this to a session will trap huge amounts of data so I created a new XE session with the previous Events but added filters for the client_app_name and the new event with some filters to avoid certain database_ids. I also altered the options parameter TRACK_CAUSALITY which we will review below the code. Switching TRACK_CAUSALITY=ON means that all events get an extra value in their data This attach_activity_id value can be used to link the deprecation_announcement and deprecation_final_support events to the module_end events, thus giving us the module (Procedure, Function, Trigger etc) that contains the deprecated code. Taking the output of the new XE session and importing it into a database table again is done We are on the home stretch now, we just need to query the XE_Deprecated_Events_TwoPartNames_02 table and tie the deprecation events to their associated module_end events and find where we need to focus the attention of the development team so that they can alter the code to comply with upcoming versions of SQL Server. The MSDN information explains in detail that when you turn on Causality Tracking each event that gets fired is given a unique Activity ID which is comprised of a GUID for each task and a sequence number for each event that is fired within that task. Taking our extract of example XML above, we would see the GUID and the sequence number as shown below. 1820-guid.png In order for us to link the events from both the deprecation events and the module_end events we need to link the data we have by the GUID part of the Activity_ID and then sort by the sequence number. To do this effectively over a large number of events I found it best to alter the table and create a column specifically for the GUID part of the Activity_ID and then create an index on it. Then, again for performance reasons, I select all the deprecation_events into a temporary table and all the module_end events into another and then join both of those back to the complete set of data. 1820-eaaf6fd4-32b1-4d11-b3ad-0d2ca8d9ec8 Now all we need do is take the results and break the news gently to the developers. Giving them a detailed list of database objects to focus on is a much better way for them to tackle this sort of problem rather than watching them review every object in the database trying to hunt down code issues. It will also let them prioritise both the order that work is done and the resources that are put on the work when they see how big the list of changes is. Wish me luck!

FAQs

1. How do I prepare to upgrade SQL Server?

Five-stage approach. (1) Run the Database Migration Assistant (DMA) against each database – it statically analyses schemas and scripts for compatibility issues with the target version and produces an assessment report. For Azure migrations, Azure Migrate: Database Migration is the equivalent. (2) Identify deprecated features actually in use at runtime (DMA catches compile-time issues but not every runtime path): query sys.dm_os_performance_counters for deprecation counters, and capture sqlserver.deprecation_announcement and sqlserver.deprecation_final_support events with Extended Events to see which specific queries and applications trigger them. (3) Remediate: rewrite queries, update application code, or plan workarounds for features that can’t be easily replaced. (4) Test on a non-production environment running the target SQL Server version with a workload replay. (5) Plan the upgrade itself (in-place vs side-by-side, backup and rollback strategy, downtime window, post-upgrade validation checklist). This article focuses on stage 2 – the runtime-detection piece that complements DMA’s static analysis.

2. What is sys.dm_os_performance_counters used for in SQL Server upgrade planning?

sys.dm_os_performance_counters is a DMV that exposes the internal SQL Server performance counters – the same counters visible in Windows Performance Monitor. For upgrade planning, the ‘SQLServer:Deprecated Features’ counter object tracks each deprecated feature’s usage count since SQL Server started. Query: SELECT object_name, counter_name, cntr_value FROM sys.dm_os_performance_counters WHERE counter_name LIKE ‘%deprecated%’ ORDER BY cntr_value DESC. High cntr_value indicates the deprecated feature is being used frequently on this instance; zero indicates it’s either not used or the instance was recently restarted. This gives you the WHICH (which features are in use) but not the WHERE (which applications or queries use them) – for that, Extended Events capture is needed.

3. What is the difference between deprecation_announcement and deprecation_final_support in SQL Server?

These are two Extended Events raised when queries use deprecated features, with different urgency levels. deprecation_announcement fires for features that Microsoft has announced will be removed but will remain available for at least the next three SQL Server versions – these are advance warnings for forward planning. deprecation_final_support fires for features that will be removed in the next version – these are urgent: queries using them will fail after the upgrade. An Extended Events session capturing both gives you the full picture, with priority routing based on event name: deprecation_final_support events need immediate remediation, deprecation_announcement events can be scheduled as part of broader refactoring work.

4. How do I capture deprecated feature usage with Extended Events in SQL Server?

Create an XE session that captures both deprecation events along with the SQL text and client identification. Example: CREATE EVENT SESSION [DeprecatedFeatureTracking] ON SERVER ADD EVENT sqlserver.deprecation_announcement (ACTION (sqlserver.sql_text, sqlserver.session_id, sqlserver.client_app_name, sqlserver.database_name)), ADD EVENT sqlserver.deprecation_final_support (ACTION (sqlserver.sql_text, sqlserver.session_id, sqlserver.client_app_name, sqlserver.database_name)) ADD TARGET package0.event_file (SET filename = ‘C:\XE\Deprecated.xel’) WITH (STARTUP_STATE = ON). Start the session, let it run for a representative period (typically several days to capture monthly, weekly, and daily workloads), then read the captured data with sys.fn_xe_file_target_read_file to see exactly which SQL statements and which applications are triggering each deprecation event. Correlate with the Extended Events tutorial earlier in this change pack for XE session management details.

This document contains proprietary information and is protected by copyright law.

Copyright © 2026 Red Gate Software Limited. All rights reserved

Article tags

About the author

Jonathan Allen

See Profile

Jonathan Allen has been a SQL Server DBA since 1999, most enjoying performance tuning and development but also working with SSIS, SSRS to provide suitable business solutions. He is SQLSouthWest PASS Chapter Leader, blogs for Simple Talk, is a forum moderator at ask.sqlservercentral.com and is on Twitter. If you would like to find your nearest user group or just want to say hello then he would love to get an email from you.

Jonathan Allen's contributions