Audit Per-Database MAXDOP, CE and Sniffing Config Overrides
A database restored from another server, or built by a vendor's install script, can carry its own MAXDOP, cardinality estimation model or parameter sniffing setting, and that setting overrides the server-wide default. The query below lists every database scoped option in the current database, one row per configuration, with the value the primary uses next to the value its secondaries use. Run it once in each database you are checking.
Purpose and Overview
One database starts producing serial plans, or plans built on the old cardinality estimator. Every other database on the instance behaves, and the server-level max degree of parallelism is where it should be. The cause sits one level down. Database scoped options show up only in sys.database_scoped_configurations, as overrides to server-wide default settings, and sys.configurations shows server-wide settings only.
The view exists in SQL Server 2016 (13.x) and later. The query sticks to the 2016 column set. It leaves out is_value_default, which was added in SQL Server 2017, so the same text runs on 2016 and on every later version.
Code Breakdown
The query reads every row of sys.database_scoped_configurations for the current database and carries a commented-out plan-cache flush.
1-- Get database scoped configuration values for current database (Query 55) (Database-scoped Configurations)
2SELECT configuration_id, name, [value] AS [value_for_primary], value_for_secondary
3FROM sys.database_scoped_configurations WITH (NOLOCK) OPTION (RECOMPILE);
4------
5
6-- This lets you see the value of these new properties for the current database
7
8-- Clear plan cache for current database
9-- ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
10
11-- ALTER DATABASE SCOPED CONFIGURATION (Transact-SQL)
12-- https://bit.ly/2sOH7nb
The column list and the value_for_primary alias
configuration_id is an int ID for the option and name is nvarchar(60). Both value and value_for_secondary are sql_variant. That type lets one column hold a MAXDOP count, a 1 or 0 flag, and the 1,440-minute default of PAUSED_RESUMABLE_INDEX_ABORT_DURATION_MINUTES.
The alias [value] AS [value_for_primary] only renames the column. value holds the setting for the primary replica, and the new name puts it side by side with value_for_secondary. That way nobody reads value as the only setting in play.
The number of rows depends on the version. IDENTITY_CACHE applies to SQL Server 2017 (14.x) and later, so a 2016 result does not include it. Some names also changed starting with SQL Server 2019: DISABLE_INTERLEAVED_EXECUTION_TVF became INTERLEAVED_EXECUTION_TVF. If you compare results across instances by matching on name, map renamed options between 2017 and 2019 or they will show up as missing on one side.
WITH (NOLOCK) and OPTION (RECOMPILE)
WITH (NOLOCK) reads the view without waiting on shared locks. OPTION (RECOMPILE) compiles a fresh plan on each run instead of reusing a cached one.
Reading MAXDOP, CE, sniffing and hotfix values against the server default
For MAXDOP, a value of 0 is the default and means the server configuration is used. Any other number overrides the max degree of parallelism set by sp_configure. Two layers sit above the database value: a query hint overrides both the server and the database setting, and Resource Governor can cap all other MAXDOP settings. The limit applies per task, not per request or per query.
Azure SQL Database starts from a different baseline. New single and elastic pool databases start at MAXDOP 8, so on those databases the value to compare against is 8, not 0.
On/off options read as 1 for enabled and 0 for disabled. For the three optimizer options, the default value and the override value map like this:
| Option | Default | Override reads as | Equivalent trace flag |
|---|---|---|---|
LEGACY_CARDINALITY_ESTIMATION | 0 (OFF) | 1 | 9481 |
PARAMETER_SNIFFING | 1 (ON) | 0 | 4136 |
QUERY_OPTIMIZER_HOTFIXES | 0 (OFF) | 1 | 4199 |
With LEGACY_CARDINALITY_ESTIMATION OFF, the CE model follows the database's compatibility level. A 1 pins the database to the legacy model whatever its compatibility level. PARAMETER_SNIFFING defaults to ON, so a 0 is the override here, the reverse of the other two. QUERY_OPTIMIZER_HOTFIXES OFF disables optimizer hotfixes released after the highest compatibility level available for that version.
The result has no single rule for spotting an override. PARAMETER_SNIFFING defaults to 1, MAXDOP to 0, and PAUSED_RESUMABLE_INDEX_ABORT_DURATION_MINUTES to 1,440. Read each row against its own default.
value_for_secondary and NULL
A NULL in value_for_secondary means the secondary is set to PRIMARY and follows the primary's value. PRIMARY is the default setting for the secondaries, so a column full of NULLs is normal. Any value other than NULL was set for the secondaries with FOR SECONDARY. All secondaries use the same configuration, and individual secondaries cannot have different settings.
To see the value a secondary runs with, replace the NULL with the primary's value:
1select *, isnull(value_for_secondary,value) as RealValueForSecondary from sys.database_scoped_configurations;
This ISNULL form turns the column into one you can read directly.
The commented CLEAR PROCEDURE_CACHE line
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE clears the plan cache for the current database. The script leaves it commented out so that running the audit never flushes plans. After a SET change you do not need it, because every ALTER DATABASE SCOPED CONFIGURATION statement already clears that database's procedure cache.
Key Benefits and Use Cases
- Vendor database intake — a vendor install that switches on legacy CE or switches off sniffing shows up in one query, before anyone opens a ticket about slow plans.
- Trace flag audit — flags 9481, 4136 and 4199 each have a scoped equivalent, so the result shows which databases already carry the per-database version of a flag.
- Down-level export check — a DACPAC or BACPAC from a database that uses scoped configurations can't be imported into SQL Server 2014 (12.x) or earlier, so check the database before planning that move.
- Cross-database query triage — a three-part name query runs under the settings of the connection's current database, except SQL modules compiled in another database, so audit the database the application connects to as well as the one holding the tables.
- Low-privilege monitoring — reading the view requires only the public role, so a monitoring login can run it without sysadmin.
Performance Considerations
- Read cost: the query reads one catalog view in the current database, so it is cheap to run during working hours.
- Change cost: any
ALTER DATABASE SCOPED CONFIGURATIONclears the current database's procedure cache and all queries have to recompile, so make changes during a quiet window. - Other ALTERs flush too: changes to database options, collation, compatibility level and filegroup properties also invalidate the database's plan cache, so plan for the same recompile cost.
- Failover: recompile doesn't occur on failover, so a new primary keeps running cached queries built under the secondary settings while new queries pick up the settings that apply to them.
- Diagnostic options left on:
FORCE_SHOWPLAN_RUNTIME_PARAMETER_COLLECTION(SQL Server 2022 and later) adds extra and possibly significant CPU and memory overhead and is meant for time-limited troubleshooting, so a 1 in that row belongs on the list of things to turn off.
Practical Tips
- Sweep the instance first — the "Non-Default Database Scoped Config" check in sp_Blitz covers every database, and this query then gives the row-level detail in the databases it flags.
- Check one option directly —
SELECT name, value, value_for_secondary FROM sys.database_scoped_configurations WHERE [name] = 'LEGACY_CARDINALITY_ESTIMATION';returns the single row when you only need to confirm one setting. - Log every change — the ALTER_DATABASE_SCOPED_CONFIGURATION DDL event can fire a DDL trigger that records who changed which option and when.
- Reset a secondary override —
ALTER DATABASE SCOPED CONFIGURATION FOR SECONDARY SET MAXDOP = PRIMARY;puts the secondaries back on the primary's value. - Grant the narrow permission — changes need ALTER ANY DATABASE SCOPED CONFIGURATION, which a user with CONTROL on the database can grant:
GRANT ALTER ANY DATABASE SCOPED CONFIGURATION TO [Joe];.
Conclusion
The query is a first check for per-database overrides that sys.configurations and sp_configure never show. Run it after every restore or migration and before tuning a database that behaves differently from its neighbours. Use the sp_Blitz check when you need an instance-wide sweep.
References
- SQL Server 2019 Diagnostic Information Queries (ktaranov/sqlserver-kit) — the script (Query 55) and its current-database comment
- sys.database_scoped_configurations (Transact-SQL), Microsoft Learn — minimum version, column types, is_value_default in 2017, NULL secondary meaning, carry-over on restore and attach, public role permission
- ALTER DATABASE SCOPED CONFIGURATION (Transact-SQL), Microsoft Learn — option defaults, trace flag equivalents, MAXDOP precedence, metadata note on sys.configurations, plan cache clearing and invalidation, failover behaviour, three-part name settings, DacFx export limit, FORCE_SHOWPLAN overhead, single-option check query, permissions, DDL event, version and name changes
- Database Scoped Configurations, SQLServerCentral — ISNULL query for the effective secondary value; FOR SECONDARY reset statement
- sp_Blitz.sql (BrentOzarULTD/SQL-Server-First-Responder-Kit) — "Non-Default Database Scoped Config" instance-wide check
Posts in this series
- SQL Server Scripts and Commands: DBA Reference All Versions
- SQL Server DBCC CHECKIDENT: Bulk Identity Column Analysis
- SQL Server Error Log Search Script: xp_readerrorlog
- SQL Server Search Stored Procedure and View Text
- SQL Server Agent Job Failure History Report
- SQL Server Kill Sessions: Filtered SPID Management
- SQL Server MAXDOP Recommendation Script
- SQL Server Max Server Memory Calculator Script
- SQL Server Object Dependencies Report: Find All References
- SQL Server DBCC CHECKIDENT: Check and Reseed Identity
- List All Tables Across All Databases in SQL Server
- Configure Database Mail and Send a Test Message
- Audit Server Configuration Drift with sys.configurations
- Check AG Replica Health with sys.dm_hadr_availability_replica_states
- Audit Per-Database MAXDOP, CE and Sniffing Config Overrides