Understanding how to enable SQL Server Optimizer Hotfixes

There are a number of knobs and switches that are available to database administrators that can be used to enable better performance.  There are three options in particular that this blog will be discussing, trace flag 4199, the database scoped configuration QUERY_OPIMIZER_HOTFIXES and the qeury hint ENABLE_QUERY_OPTIMIZER_HOTFIXES. Understanding how these options function will give you a hand up on ensuring the query optimizer is running as optimally as possible.

Let’s take a look at the three options.

Trace Flag 4199

In dealing with any trace flag, it is vital that you understand as to what the trace flag will enable or disable and how it pertains to your individual workloads.  Some trace flags are benign, such as TF3226 which removes successful backup messages from the log, others can be quite intrusive and cause havoc.   Make sure you review any documentation on the respective trace flag prior to implementation.

The official verbiage from Microsoft on trace flag 4199 is:

“Enables Query Optimizer (QO) fixes released in SQL Server Cumulative Updates and Service Packs.

QO changes that are made to previous releases of SQL Server are enabled by default under the latest database compatibility level in a given product release, without trace flag 4199 being enabled.” 

What this really implies is that if your database is at the most current compatibility level for your version of SQL server, then the query optimizer will utilize all of the QO hotfixes up to the release to market (RTM) version but nothing beyond the RTM version.

For example, if you are running SQL Server 2017 CU20 the database is set at the appropriate compatibility level (140), and TF4199 is disabled, the query optimizer will only utilize any hotfixes for it up to 2017 RTM.   Any query optimizer hotfix that was delivered in subsequent cumulative updates will not be utilized.

If you enable trace flag 4199, this instructs SQL Server to implement any query optimizer hotfix that was delivered after the RTM version.   Note that enabling this trace flag will be applied across all databases.  It’s an all or nothing trace flag as most trace flags are.

The table below (from Microsoft documentation explains the matrix of outcomes when dealing with trace flag enabled or disabled.

Database Engine (DE) version Database Compatibility Level TF 4199 QO changes from all previous Database Compatibility Levels QO changes for DE version post-RTM
13 (SQL Server 2016 (13.x)) 100 to 120 Off Disabled Disabled
On Enabled Enabled
130 (Default) Off Enabled Disabled
On Enabled Enabled
14 (SQL Server 2017 (14.x)) 100 to 120 Off Disabled Disabled
On Enabled Enabled
130 Off Enabled Disabled
On Enabled Enabled
140 (Default) Off Enabled Disabled
On Enabled Enabled
15 (SQL Server 2019 (15.x)) and 12 (Azure SQL Database) 100 to 120 Off Disabled Disabled
On Enabled Enabled
130 to 140 Off Enabled Disabled
On Enabled Enabled
150 (Default) Off Enabled Disabled
On Enabled Enabled

If you are running in Azure SQL Database, you don’t have the ability to enable this particular trace flag, which is where the database scoped configuration becomes useful. If you are running on Azure SQL Managed Instances, you can enable the trace flag just like you would if on-premises.

Enabling this trace flag would also require a restart of the SQL Server services if you want to persist it upon a restart. You can enable this trace flag by setting up a startup parameter in the SQL Server Configuration Manager.  You can check for the existence of trace flags by using DBCC TRACESTATUS().


Enabling trace flag 4199 is a global trace flag for the entire instance.  This means that it’ll apply the configuration across all databases.  What if you have a mixture of databases that may or may not be able to take advantage of any hotfixes?  Enabling the trace flag could cause issues.  This is where the QUERY_OPIMIZER_HOTFIXES database scoped configuration comes in to play.

This configuration allows you to enabled query optimizer hotfixes post the release to market version for any specific database. This also allows you to enable it for Azure SQL Database since we don’t have the ability to enable the trace flag within that product.


The query above has to be executed within the context of the individual database.  You can also enable this configuration in Azure SQL Managed Instances databases.


If you didn’t want to enable these hotfixes at the instance level or the database level, there’s a third option.  You can also enable it as a query hint.  Keep in mind that the query optimizer will want to pick the best execution plan possible.  Use query hints as sparingly as possible and make sure to ask yourself if you are really smarter than the optimizer.  If the answer is no, you aren’t smarter than the optimizer then don’t use a query hint.  So, it goes without saying that my recommendation is to not use query hints unless that’s the only way to solve an issue.

SELECT * FROM Person.Address 
WHERE City = 'SEATTLE' AND PostalCode = 98104


In this post I’ve shown three methods on how to implement the most recent query optimizer hot fixes.  Before putting any of them into production, make sure that you verify your respective workloads again them.  Make sure to also review all of the cumulative updates or service packs since initial release to see what query optimizer issues were fixed.  You might be missing out of a fix that will help solve a performance problem.

© 2020, John Morehouse. All rights reserved.


One Response

  1. This looks really useful! If I set TF4199 globally can I override this per database with QUERY_OPTIMIZER_HOTFIXES = OFF? thanks

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Trust DCAC with your data

Your data systems may be treading water today, but are they prepared for the next phase of your business growth?