Server Health Report – RockyPC – 2026-05-16

🎯 Tuning Goal: Server Health
Server: RockyPC (default instance)
Version: SQL Server 2022 (RTM-GDR) 16.0.1180.1
Edition: Developer Edition (64-bit) / Enterprise Engine
OS: Windows 10 Home (Build 26200) — Hypervisor
Database: master (server-wide scope)
Uptime: < 1 day (recently restarted)
Report Date: 2026-05-16 00:27:38 UTC

Executive Summary

This report analyzes the overall health of RockyPC, a single-instance SQL Server 2022 Developer Edition running on a 16-core Windows 10 workstation with 32 GB RAM. The instance hosts several databases including SQLStorm, WideWorldImporters, tpch, tpch10, tpcc, CRM, and DigitsSolver.

The server has been online for less than one day, so wait statistics and I/O metrics reflect a short observation window. Despite this, several significant operational, integrity, and configuration concerns were identified. The most urgent findings are:

🔴 CRITICAL – Database Integrity: All 7 user databases show CHECKDB has either never been run (reporting 1900-01-01) or is overdue (>30 days). This is the highest operational risk on the server and must be addressed immediately.
🔴 CRITICAL – Backup Coverage: The majority of databases have no recorded backups. Five databases with FULL recovery model have no log backups, meaning transaction logs are growing unchecked and point-in-time recovery is impossible.
🟡 HIGH – Configuration: Three important server settings are sub-optimal: optimize for ad hoc workloads is disabled, backup compression default is off, and backup checksum default is off.
🟡 MEDIUM – Query Store: WideWorldImporters has a non-standard Query Store configuration (flush interval 50 min, stats interval 15 min, max plans 1000) and runs at compatibility level 130, missing SQL Server 2022 IQP features. All other databases could benefit from reduced flush intervals for tighter workload visibility.
🔵 LOW – Wait Statistics: All top waits (PWAIT_DIRECTLOGCONSUMER_GETNEXT, QDS_PERSIST_TASK_MAIN_LOOP_SLEEP, QDS_ASYNC_QUEUE) are benign background waits. HTMEMO (1.65%) is a normal in-memory hash join wait. No user-query blocking patterns detected.
✅ Positive Findings: I/O latencies are excellent across all files (<2 ms), no missing indexes detected, no deadlocks in 7 days, only 1 sysadmin member, all active connections are encrypted (the single unencrypted telemetry session via shared memory is minimal risk), and Query Store is enabled on all databases.

Top Priorities

# Issue Severity Category Confidence
1 CHECKDB never run or overdue on all 7 user databases Critical Integrity High 95%
2 No backups for most databases; FULL recovery databases have no log backups Critical Backup/Recovery High 95%
3 WideWorldImporters on compatibility level 130 — missing SQL 2022 IQP features High Configuration High 90%
4 optimize for ad hoc workloads disabled — plan cache pollution risk High Configuration High 92%
5 Backup compression and checksum defaults disabled Medium Configuration High 95%
6 WideWorldImporters last full backup is 1,316 days old High Backup/Recovery High 95%
7 Query Store flush interval non-standard on WideWorldImporters (50 min) Medium Query Store Medium 85%
8 tempdb metadata memory-optimized disabled — potential contention under load Medium Performance Medium 80%
9 SQL Server 2022 at RTM-GDR (KB5091158) — verify patch currency Medium Operational Medium 80%
10 System databases (master, msdb, model) have no backups recorded High Backup/Recovery High 95%

1. Performance Improvements

Medium Enable Memory-Optimized TempDB Metadata Confidence 80%

The setting tempdb metadata memory-optimized is currently disabled (0). On SQL Server 2022 with an Enterprise engine, enabling this feature moves system table metadata (such as sysobjects, sysrowsets, sysallocunits) to memory-optimized tables, dramatically reducing latch contention under heavy tempdb usage. While current tempdb I/O is very low, enabling this proactively prevents future bottlenecks as workloads grow.

Action: Enable via sp_configure and restart the SQL Server service. See the Scripts section for the configuration change.

Low Wait Statistics — Background Waits Only (Healthy) Confidence 95%

The top four wait types are all normal background waits with no user query impact:

  • PWAIT_DIRECTLOGCONSUMER_GETNEXT (42.56%): Query Store log consumer waiting for new log records. Normal and expected when Query Store is active.
  • QDS_PERSIST_TASK_MAIN_LOOP_SLEEP (42.37%): Query Store persistence task sleeping between flush cycles. Completely benign.
  • QDS_ASYNC_QUEUE (12.48%): Query Store asynchronous background queue. Normal when Query Store is enabled.
  • HTMEMO (1.65%): In-memory hash join memoization wait. Normal for analytical queries (tpch/tpcc/tpch10 workloads).

No CPU pressure, memory pressure, or I/O bottleneck waits are present. The server is in excellent performance health during this short observation window.

Low I/O Subsystem — Excellent Latencies Confidence 95%

All database files show average I/O latencies of 0–1 ms, well within best-practice thresholds (<5 ms for SSD, <20 ms for spinning disk). Data and log files are appropriately separated between C:\Data\ and C:\Logs\. The SQLStorm MDF file has the highest read volume (128 MB, 1,554 reads) and remains at 1 ms average — no concern.

Observation: System database files (master, msdb, model, tempdb) are all stored under C:\Data\MSSQL16.MSSQLSERVER\MSSQL\DATA\ on the same volume as user databases. This is acceptable for a developer workstation but would be a concern in production.

tempdb Configuration: 8 data files (tempdev + temp2–temp8) are configured, which is excellent and matches the logical CPU count guideline (8 = max recommended for 16 cores).

Medium Max Server Memory — Review Ceiling Confidence 75%

max server memory is set to 23,168 MB (~71% of 32,527 MB total RAM). Current committed memory is only 1,510 MB (committed target: 7,872 MB), reflecting the recent restart. The 23 GB ceiling is reasonable for a developer machine that also runs an OS and other applications. No action required unless memory pressure appears after workloads warm up. Monitor sys.dm_os_memory_clerks after the instance has been running for several hours.

2. Configuration Optimizations

High Enable "Optimize for Ad Hoc Workloads" Confidence 92%

Currently set to 0 (disabled). When disabled, the first execution of any ad hoc query stores the full compiled plan in the plan cache, consuming buffer pool memory even for single-use queries. Enabling this setting stores only a stub on first execution, dramatically reducing plan cache bloat — a universal best practice with zero negative impact.

Action: See Scripts — "Enable Optimize for Ad Hoc Workloads".

High Enable Backup Compression Default Confidence 95%

backup compression default is disabled (0). Compressed backups are significantly smaller (typically 50–70% reduction) and complete faster due to reduced I/O. On SQL Server 2022 with the default algorithm (VDI-based), the CPU overhead is minimal on modern hardware. This is a best-practice setting for all editions that support it.

Action: See Scripts — "Enable Backup Compression and Checksum Defaults".

High Enable Backup Checksum Default Confidence 95%

backup checksum default is disabled (0). Backup checksums validate backup integrity during both backup creation and restore verification, catching I/O corruption early. This is a critical reliability feature with negligible performance impact.

Action: Included in the "Enable Backup Compression and Checksum Defaults" script.

High Upgrade WideWorldImporters Compatibility Level to 160 Confidence 90%

WideWorldImporters is running at compatibility level 130 (SQL Server 2016). All other user databases are at 160 (SQL Server 2022). At level 130, this database misses out on significant features available in levels 140–160:

  • Adaptive Query Processing (level 140+): adaptive joins, interleaved execution, memory grant feedback
  • Intelligent Query Processing (level 150+): table variable deferred compilation, scalar UDF inlining, batch mode on rowstore
  • SQL Server 2022 IQP (level 160): Parameter Sensitive Plan optimization, DOP feedback, CE feedback

Action: Test the workload in a staging environment first, then upgrade. See Scripts — "Upgrade WideWorldImporters Compatibility Level".

Medium Cost Threshold for Parallelism — Consider Increasing Confidence 70%

cost threshold for parallelism is set to 30 (non-default; the default is 5). This is already a positive improvement over the default. For mixed OLTP/analytical workloads (tpcc + tpch), a value of 30–50 is commonly recommended. The current value of 30 appears appropriate. Monitor for excessive parallelism under concurrent load and consider increasing to 50 if needed.

Medium Max Degree of Parallelism — Verify for Workload Confidence 75%

MAXDOP is set to 8 on a 16-logical-core, single-socket machine. This follows the standard Microsoft recommendation (cap at 8 for single-socket systems). No changes needed unless specific query performance issues arise. DOP feedback (SQL 2022 level 160) will automatically adjust per-query DOP over time for Query Store-tracked databases.

Low Enable "Blocked Process Threshold" Monitoring Confidence 80%

blocked process threshold is set to 0 (disabled). Setting this to 5–10 seconds enables the Blocked Process Report extended event, which provides automatic detection and reporting of blocking chains. Recommended for any active OLTP workload.

Action: See Scripts — "Enable Blocked Process Threshold".

3. Index Optimization Opportunities

Low No High-Value Missing Indexes Detected Confidence 90%

The missing index DMV analysis across all databases returned no high-impact missing indexes. This is consistent with the server having been online for less than one day — the DMVs reset on service restart and insufficient query volume has accumulated to generate meaningful recommendations.

Recommendation: Re-run the Index Tuning goal analysis after the server has been under representative workload for at least 24–72 hours. At that point, the missing index DMVs will reflect actual query patterns. The Index Tuning goal in AI SQL Tuner Studio can be applied per-database (SQLStorm, tpcc, tpch, tpch10, WideWorldImporters, CRM, DigitsSolver) for a comprehensive analysis.

Low Consider Columnstore Indexes for Analytical Databases Confidence 75%

The presence of tpch and tpch10 (TPC-H benchmarks) indicates analytical/reporting workloads with large table scans. These workloads are ideal candidates for clustered or non-clustered columnstore indexes, which are available on the Enterprise engine and can deliver 10–100x performance improvements for analytical queries. The HTMEMO wait (hash join memoization) on these databases is consistent with this workload profile.

Action: After running the Index Tuning goal for tpch and tpch10, specifically evaluate columnstore index opportunities on large fact tables.

4. Query Store Optimization

High WideWorldImporters — Standardize Query Store Configuration Confidence 85%

WideWorldImporters has a non-standard Query Store configuration compared to all other databases on this instance:

  • Flush Interval: 50 minutes vs. 15 minutes (all others) — data loss window is 3× larger
  • Stats Collection Interval: 15 minutes vs. 60 minutes (all others) — higher granularity is fine but inconsistent
  • Max Plans Per Query: 1,000 vs. 200 (all others) — increases storage overhead
  • Max Storage: 500 MB vs. 1,000 MB (all others) — may cap earlier under active workloads

Recommendation: Standardize to the consistent settings used by other databases: 15-min flush, 60-min stats interval, 200 max plans, 1,000 MB storage, and upgrade compatibility to 160. See Scripts — "Standardize WideWorldImporters Query Store Settings".

Medium All Databases — Query Store Configuration Is Generally Healthy Confidence 90%

All six non-WWI databases have Query Store in READ_WRITE mode with AUTO cleanup and capture, 1,000 MB storage limit, 15-minute flush interval, and 30-day stale query threshold. Storage utilization is minimal (0.1–0.8%), indicating Query Store is functioning correctly and not under pressure.

Positive: All databases are at compatibility level 160, enabling full SQL Server 2022 IQP features including DOP Feedback, CE Feedback, and Parameter Sensitive Plan optimization — which rely on Query Store data to function.

Optional Enhancement: Consider enabling QUERY_CAPTURE_MODE = CUSTOM with appropriate thresholds to filter out low-frequency, low-resource queries from storage, keeping Query Store data focused on meaningful workloads. This is optional for a developer environment but good practice.

5. Database Integrity Maintenance (CHECKDB)

CRITICAL: All 7 user databases show CHECKDB has either never been run or is more than 30 days overdue. The 1900-01-01 date indicates the database was never successfully checked, not that the check failed — it simply has no record in sys.databases.create_date integrity tracking. This must be rectified immediately.
Critical Run DBCC CHECKDB on All User Databases Immediately Confidence 95%

The following databases have never had CHECKDB recorded (showing 1900-01-01):

  • WideWorldImporters
  • SQLStorm
  • tpcc
  • tpch
  • CRM
  • tpch10

DigitsSolver was last checked on April 12, 2026 (33 days ago — marginally overdue per the 30-day threshold). Re-run is recommended.

Recommended Schedule:

  • Immediately: Run DBCC CHECKDB with PHYSICAL_ONLY on all databases to quickly detect physical corruption.
  • Weekly (or bi-weekly): Full DBCC CHECKDB (all checks) on smaller databases (CRM, DigitsSolver, master, msdb, model).
  • Monthly: Full DBCC CHECKDB on larger databases (WideWorldImporters, SQLStorm, tpcc, tpch, tpch10).

Note: This is a developer workstation — on production systems, CHECKDB should run at minimum weekly. Since this is Developer Edition, schedule via SQL Agent jobs or Windows Task Scheduler.

See Scripts — "Run DBCC CHECKDB on All User Databases" and "Schedule Weekly CHECKDB via SQL Agent".

6. Security Enhancements

Low Connection Encryption — All User Sessions Encrypted ✅ Confidence 95%

All 10 active user sessions are encrypted. The one unencrypted session (Session 67) belongs to NT SERVICE\SQLTELEMETRY running the SQL Server CEIP (Customer Experience Improvement Program) via shared memory. As explicitly noted in the analysis instructions, shared memory connections are local-only and carry minimal risk — no user data is exposed. No action required.

Note: All connections use NTLM Windows Authentication over shared memory (local machine only). If remote TCP connections are added in future, ensure TLS is configured via SQL Server Configuration Manager with a valid certificate.

Low Sysadmin Membership — Minimal and Appropriate ✅ Confidence 95%

Only one sysadmin member exists: RockyPC\k_a_f (the local Windows account, expected for a developer workstation). This follows least-privilege principles. No built-in sa account or additional privileged accounts detected.

Best Practice Reminder: Periodically audit sysadmin membership with the script in the Scripts section. Ensure that if this machine is ever connected to a domain or shared environment, unnecessary principals are not added.

Medium Mixed Mode Authentication Is Enabled Confidence 80%

Integrated Security Only = No indicates the server is configured for Mixed Mode Authentication (both Windows and SQL Server logins accepted). For a local developer workstation this is common and acceptable, but it introduces the risk of weak SQL logins if any are created.

Recommendation: Audit existing SQL Server logins and ensure the sa account is disabled or has a strong password. See Scripts — "Audit SQL Logins and sa Account Status".

7. Concurrency Issues

Low No Deadlocks Detected — Healthy ✅ Confidence 95%

No deadlocks were detected in the system health session extended events over the past 7 days. No deadlock analysis or Fix Deadlocks goal engagement is needed at this time.

Low Enable Blocked Process Threshold for Proactive Monitoring Confidence 82%

As noted in Configuration (#7), blocked process threshold is currently 0. Setting it to 5 seconds enables automatic blocked process report events that can be captured via Extended Events or the system health session, making it easy to detect blocking chains before they escalate.

8. Backup & Recovery

CRITICAL: The majority of databases on this instance have no recorded backups. While this is a developer machine, the data in SQLStorm, CRM, DigitsSolver, tpcc, tpch, and tpch10 is at risk of permanent loss in the event of storage failure or accidental corruption.
Critical Establish Immediate Full Backup for All User Databases Confidence 95%

The following databases have no recorded full backup:

  • CRM (FULL recovery — log growing, no protection)
  • DigitsSolver (FULL recovery — log growing, no protection)
  • tpcc (FULL recovery — log growing, no protection)
  • tpch10 (FULL recovery — log growing, no protection)
  • master, msdb, model (system databases)

WideWorldImporters: Last full backup was October 7, 2022 (1,316 days ago). This database is running in SIMPLE recovery, so no log backup is needed, but the backup is dangerously stale and must be refreshed.

SQLStorm: Last full backup was October 25, 2025 (202 days ago) in SIMPLE recovery. While somewhat stale, it is functional. Consider refreshing.

tpch: Last full backup was November 22, 2025 (174 days ago) in FULL recovery with no log backups. The transaction log has been growing unchecked since then — this can cause disk space exhaustion. Immediate action needed: either switch to SIMPLE recovery or implement log backup jobs.

See Scripts — "Full Backup All User Databases" and "Fix Full Recovery Log Backup Gap".

High Fix Full Recovery Databases Without Log Backups Confidence 95%

The following databases are in FULL recovery model but have no log backups. In this state, the transaction log cannot be truncated and will grow until disk space is exhausted. Additionally, point-in-time recovery (the primary benefit of FULL recovery) is not achievable without a continuous log backup chain:

  • model (system DB — FULL recovery, no log backups)
  • DigitsSolver
  • CRM
  • tpcc
  • tpch
  • tpch10

Decision Required: For each database, choose one of:

  1. Switch to SIMPLE recovery if point-in-time recovery is not needed (appropriate for most developer databases).
  2. Implement regular log backups (every 15–60 minutes) to enable point-in-time recovery and allow log truncation.

See Scripts — "Fix Full Recovery Log Backup Gap".

9. Operational Best Practices

Medium Apply Latest SQL Server 2022 Cumulative Update Confidence 80%

The instance is running 16.0.1180.1 (RTM-GDR, KB5091158) dated April 16, 2026. This appears to be a very recent GDR patch. Verify that this is the latest available GDR or CU by checking the SQL Server 2022 build history. GDR releases contain critical security fixes only; Cumulative Updates (CUs) also include bug fixes and performance improvements. For a developer environment, tracking the latest CU is recommended.

Note: Product Update Level shows "(unknown)" — this may indicate the patch level property is not set in this GDR. Confirm actual patch level via SELECT @@VERSION.

Medium SQL Server Agent — Establish Maintenance Jobs Confidence 90%

SQL Server Agent is running (Agent XPs = 1). Leverage it to automate:

  • DBCC CHECKDB — weekly/monthly schedule per database size
  • Index maintenance — rebuild/reorganize based on fragmentation thresholds (Ola Hallengren's maintenance solution is recommended)
  • Statistics update — weekly or after large data loads
  • Database backups — daily full + log backups where applicable
  • Query Store cleanup — Query Store AUTO cleanup is enabled but manual purge scripts can help after bulk test runs
Low Developer Edition Not Licensed for Production Use Confidence 99%

This server runs Developer Edition, which has full Enterprise feature parity but is licensed for development and testing only. If any of these databases are used in a production capacity or are accessed by end users, the instance must be re-licensed with an appropriate Standard or Enterprise edition.

Low Enable Database Mail for Alert Notifications Confidence 70%

Database Mail XPs is disabled. Enabling Database Mail and configuring SQL Agent alerts for severity 16+ errors, 823/824/825 I/O errors, and maintenance job failures provides proactive notification of critical issues without requiring manual monitoring.

Low Consider Enabling Tempdb Metadata Memory-Optimized for Production-like Testing Confidence 75%

When running benchmark workloads (tpcc, tpch) that stress tempdb, enabling tempdb metadata memory-optimized will prevent tempdb system table latch contention under high concurrency. This requires a service restart but is non-disruptive on a developer machine.


Wait Analysis Reference

Wait Type % Total Tasks Total Wait Max Wait Assessment
PWAIT_DIRECTLOGCONSUMER_GETNEXT 42.56% 1,096 90.41 min 5,030 ms Benign — QDS log consumer
QDS_PERSIST_TASK_MAIN_LOOP_SLEEP 42.37% 91 90.02 min 60,029 ms Benign — QDS flush sleep
QDS_ASYNC_QUEUE 12.48% 14 26.51 min 408,799 ms Benign — QDS background queue
HTMEMO 1.65% 112 3.51 min 15,732 ms Benign — Hash join memoization

Interpretation: The top three waits are entirely driven by Query Store background activity. The overwhelming dominance of QDS waits (97%) in the wait statistics immediately after server startup is expected — QDS initializes its log consumer threads, persistence tasks, and async queues on startup. These waits will normalize as user workload accumulates. No performance bottleneck is indicated.

I/O Analysis Reference

Database File Reads Read MB Writes Write MB Avg Latency Status
SQLStorm ROWS 1,554 128 102 37 1 ms Excellent
WideWorldImporters LOG 571 258 18 0 1 ms Excellent
tpch ROWS 425 26 1 0 0 ms Excellent
SQLStorm LOG 32 1 232 7 0 ms Excellent
tpch10 ROWS 426 26 1 0 0 ms Excellent
All others All showing 0 ms average latency — no concerns. Excellent

All files are performing at sub-millisecond to 1 ms latency, consistent with NVMe SSD or high-performance local storage. No I/O tuning is required.


Scripts

The following scripts implement the recommendations in this report. Each script is a complete, runnable T-SQL batch. Review and test in a non-production environment before execution. Scripts that require a service restart are clearly marked.

1. Enable Optimize for Ad Hoc Workloads (Recommendation 2.1)

-- Enable 'optimize for ad hoc workloads' to reduce single-use plan cache bloat.
-- This is a dynamic setting; no service restart required.
-- Applies to: RockyPC (server-wide)

USE master;
GO

EXEC sp_configure 'show advanced options', 1;
RECONFIGURE WITH OVERRIDE;
GO

EXEC sp_configure 'optimize for ad hoc workloads', 1;
RECONFIGURE WITH OVERRIDE;
GO

-- Verify
SELECT name, value, value_in_use, description
FROM sys.configurations
WHERE name = 'optimize for ad hoc workloads';
GO

2. Enable Backup Compression and Checksum Defaults (Recommendations 2.2 and 2.3)

-- Enable backup compression default and backup checksum default.
-- These are dynamic settings; no service restart required.
-- Applies to: RockyPC (server-wide)

USE master;
GO

EXEC sp_configure 'show advanced options', 1;
RECONFIGURE WITH OVERRIDE;
GO

-- Enable backup compression (reduces backup size by ~50-70%)
EXEC sp_configure 'backup compression default', 1;
RECONFIGURE WITH OVERRIDE;
GO

-- Enable backup checksum (validates integrity during backup and restore)
EXEC sp_configure 'backup checksum default', 1;
RECONFIGURE WITH OVERRIDE;
GO

-- Verify
SELECT name, value, value_in_use, description
FROM sys.configurations
WHERE name IN ('backup compression default', 'backup checksum default');
GO

3. Enable Blocked Process Threshold (Recommendations 2.7 / 7.2)

-- Enable blocked process threshold monitoring (fires when blocking exceeds 5 seconds).
-- This is a dynamic setting; no service restart required.
-- Captures blocked process reports via system health extended event session.
-- Applies to: RockyPC (server-wide)

USE master;
GO

EXEC sp_configure 'show advanced options', 1;
RECONFIGURE WITH OVERRIDE;
GO

EXEC sp_configure 'blocked process threshold (s)', 5;
RECONFIGURE WITH OVERRIDE;
GO

-- Verify
SELECT name, value, value_in_use, description
FROM sys.configurations
WHERE name = 'blocked process threshold (s)';
GO

4. Enable Memory-Optimized TempDB Metadata (Recommendation 1.1)

-- Enable memory-optimized tempdb metadata to reduce system table latch contention.
-- *** IMPORTANT: Requires SQL Server service restart to take effect. ***
-- Plan a maintenance window before applying this change.
-- Applies to: RockyPC (server-wide, SQL Server 2019+ Enterprise/Developer)

USE master;
GO

EXEC sp_configure 'show advanced options', 1;
RECONFIGURE WITH OVERRIDE;
GO

EXEC sp_configure 'tempdb metadata memory-optimized', 1;
RECONFIGURE WITH OVERRIDE;
GO

-- Verify current setting (change takes effect after service restart)
SELECT name, value, value_in_use, description
FROM sys.configurations
WHERE name = 'tempdb metadata memory-optimized';
GO

-- After restarting the SQL Server service, verify with:
-- SELECT CASE WHEN OBJECTPROPERTY(OBJECT_ID('tempdb.sys.sysrowsets'),'TableIsMemoryOptimized') = 1
--             THEN 'Memory-Optimized TempDB Metadata: ENABLED'
--             ELSE 'Memory-Optimized TempDB Metadata: DISABLED'
--        END AS status;
GO

5. Upgrade WideWorldImporters Compatibility Level to 160 (Recommendation 2.4)

-- Upgrade WideWorldImporters database compatibility level from 130 to 160.
-- This enables SQL Server 2022 Intelligent Query Processing features.
-- *** TEST IN STAGING FIRST — query plan changes may affect performance. ***
-- Uses Query Store to capture plan regressions (Query Store is already enabled).

USE master;
GO

-- Step 1: Ensure Query Store is capturing baseline plans BEFORE upgrade
--         (already READ_WRITE, so baseline is being captured)

-- Step 2: Upgrade compatibility level
ALTER DATABASE [WideWorldImporters]
SET COMPATIBILITY_LEVEL = 160;
GO

-- Step 3: Verify
SELECT name, compatibility_level
FROM sys.databases
WHERE name = 'WideWorldImporters';
GO

-- Step 4: If plan regressions occur after upgrade, use Query Store
--         to force the old plan while investigating:
-- USE [WideWorldImporters];
-- EXEC sp_query_store_force_plan @query_id = , @plan_id = ;
GO

6. Standardize WideWorldImporters Query Store Settings (Recommendation 4.1)

-- Standardize WideWorldImporters Query Store configuration to match other databases.
-- Changes flush interval to 15 min, stats interval to 60 min,
-- max plans per query to 200, and max storage to 1000 MB.

USE master;
GO

ALTER DATABASE [WideWorldImporters]
SET QUERY_STORE = ON
(
    OPERATION_MODE            = READ_WRITE,
    CLEANUP_POLICY            = (STALE_QUERY_THRESHOLD_DAYS = 30),
    DATA_FLUSH_INTERVAL_SECONDS = 900,      -- 15 minutes (was 50 min = 3000 sec)
    INTERVAL_LENGTH_MINUTES   = 60,         -- Stats collection interval (was 15 min)
    MAX_STORAGE_SIZE_MB       = 1000,       -- Storage ceiling (was 500 MB)
    QUERY_CAPTURE_MODE        = AUTO,
    MAX_PLANS_PER_QUERY       = 200,        -- Max plans (was 1000)
    SIZE_BASED_CLEANUP_MODE   = AUTO
);
GO

-- Verify
SELECT
    d.name,
    qs.desired_state_desc,
    qs.actual_state_desc,
    qs.data_flush_interval_seconds / 60.0 AS flush_interval_min,
    qs.query_capture_mode_desc,
    qs.max_storage_size_mb,
    qs.stale_query_threshold_days,
    qs.max_plans_per_query
FROM sys.databases d
JOIN sys.database_query_store_options qs ON d.database_id = qs.database_id
WHERE d.name = 'WideWorldImporters';
GO

7. Run DBCC CHECKDB on All User Databases (Recommendation 5.1 — Quick Pass)

-- Run DBCC CHECKDB with PHYSICAL_ONLY on all user databases for rapid corruption detection.
-- PHYSICAL_ONLY reduces duration significantly on large databases.
-- Run the full check (without PHYSICAL_ONLY) during off-hours on a schedule.
-- *** This may take several minutes per database depending on size. ***

USE master;
GO

PRINT '== Starting DBCC CHECKDB (PHYSICAL_ONLY) for all user databases ==';
PRINT 'Start time: ' + CONVERT(VARCHAR, GETDATE(), 120);
GO

DBCC CHECKDB ([WideWorldImporters]) WITH PHYSICAL_ONLY, NO_INFOMSGS;
GO
PRINT 'WideWorldImporters: CHECKDB complete at ' + CONVERT(VARCHAR, GETDATE(), 120);
GO

DBCC CHECKDB ([SQLStorm]) WITH PHYSICAL_ONLY, NO_INFOMSGS;
GO
PRINT 'SQLStorm: CHECKDB complete at ' + CONVERT(VARCHAR, GETDATE(), 120);
GO

DBCC CHECKDB ([tpcc]) WITH PHYSICAL_ONLY, NO_INFOMSGS;
GO
PRINT 'tpcc: CHECKDB complete at ' + CONVERT(VARCHAR, GETDATE(), 120);
GO

DBCC CHECKDB ([tpch]) WITH PHYSICAL_ONLY, NO_INFOMSGS;
GO
PRINT 'tpch: CHECKDB complete at ' + CONVERT(VARCHAR, GETDATE(), 120);
GO

DBCC CHECKDB ([CRM]) WITH PHYSICAL_ONLY, NO_INFOMSGS;
GO
PRINT 'CRM: CHECKDB complete at ' + CONVERT(VARCHAR, GETDATE(), 120);
GO

DBCC CHECKDB ([tpch10]) WITH PHYSICAL_ONLY, NO_INFOMSGS;
GO
PRINT 'tpch10: CHECKDB complete at ' + CONVERT(VARCHAR, GETDATE(), 120);
GO

DBCC CHECKDB ([DigitsSolver]) WITH PHYSICAL_ONLY, NO_INFOMSGS;
GO
PRINT 'DigitsSolver: CHECKDB complete at ' + CONVERT(VARCHAR, GETDATE(), 120);
GO

-- System databases
DBCC CHECKDB ([master])  WITH PHYSICAL_ONLY, NO_INFOMSGS;
DBCC CHECKDB ([model])   WITH PHYSICAL_ONLY, NO_INFOMSGS;
DBCC CHECKDB ([msdb])    WITH PHYSICAL_ONLY, NO_INFOMSGS;
GO
PRINT 'System databases: CHECKDB complete at ' + CONVERT(VARCHAR, GETDATE(), 120);
GO

-- Verify last CHECKDB dates after completion
SELECT
    d.name AS database_name,
    DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS last_good_checkdb,
    DATEDIFF(DAY, CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS DATETIME), GETDATE()) AS days_since_checkdb
FROM sys.databases d
WHERE d.database_id > 0
  AND d.state_desc = 'ONLINE'
ORDER BY days_since_checkdb DESC;
GO

8. Schedule Weekly CHECKDB via SQL Agent Job (Recommendation 5.1)

-- Create a SQL Server Agent job to run full DBCC CHECKDB on all user databases weekly.
-- Scheduled for Sunday at 2:00 AM (adjust as needed).
-- Requires SQL Server Agent to be running.

USE msdb;
GO

-- Drop existing job if it exists (for re-runability)
IF EXISTS (SELECT 1 FROM msdb.dbo.sysjobs WHERE name = N'Weekly DBCC CHECKDB - All Databases')
    EXEC msdb.dbo.sp_delete_job @job_name = N'Weekly DBCC CHECKDB - All Databases';
GO

EXEC msdb.dbo.sp_add_job
    @job_name = N'Weekly DBCC CHECKDB - All Databases',
    @enabled = 1,
    @description = N'Runs DBCC CHECKDB on all online user databases weekly to verify integrity.',
    @category_name = N'Database Maintenance';
GO

EXEC msdb.dbo.sp_add_jobstep
    @job_name = N'Weekly DBCC CHECKDB - All Databases',
    @step_name = N'Run CHECKDB on all databases',
    @subsystem = N'TSQL',
    @command = N'
DECLARE @dbname SYSNAME;
DECLARE @sql NVARCHAR(500);
DECLARE db_cursor CURSOR FOR
    SELECT name
    FROM sys.databases
    WHERE state_desc = ''ONLINE''
      AND name NOT IN (''tempdb'')
    ORDER BY name;

OPEN db_cursor;
FETCH NEXT FROM db_cursor INTO @dbname;
WHILE @@FETCH_STATUS = 0
BEGIN
    SET @sql = N''DBCC CHECKDB(['' + @dbname + N'']) WITH NO_INFOMSGS, ALL_ERRORMSGS'';
    PRINT ''Running CHECKDB on: '' + @dbname + '' at '' + CONVERT(VARCHAR, GETDATE(), 120);
    EXEC sp_executesql @sql;
    FETCH NEXT FROM db_cursor INTO @dbname;
END;
CLOSE db_cursor;
DEALLOCATE db_cursor;
',
    @on_success_action = 1,
    @on_fail_action = 2;
GO

-- Schedule: Sunday at 02:00 AM
EXEC msdb.dbo.sp_add_schedule
    @schedule_name = N'Weekly Sunday 2AM',
    @freq_type = 8,            -- Weekly
    @freq_interval = 1,        -- Sunday
    @freq_recurrence_factor = 1,
    @active_start_time = 20000; -- 02:00:00
GO

EXEC msdb.dbo.sp_attach_schedule
    @job_name = N'Weekly DBCC CHECKDB - All Databases',
    @schedule_name = N'Weekly Sunday 2AM';
GO

EXEC msdb.dbo.sp_add_jobserver
    @job_name = N'Weekly DBCC CHECKDB - All Databases',
    @server_name = N'(local)';
GO

PRINT 'Weekly DBCC CHECKDB job created successfully.';
GO

9. Full Backup All User Databases (Recommendation 8.1)

-- Perform immediate full backups of all user databases that lack recent backups.
-- Adjust @backup_path to a valid backup directory on your system.
-- Backups use WITH COMPRESSION and CHECKSUM (enabled by previous sp_configure scripts).

USE master;
GO

DECLARE @backup_path NVARCHAR(256) = N'C:\SQLBackups\';  -- *** CHANGE THIS PATH ***

-- Ensure backup directory exists (run in Windows or use xp_cmdshell if enabled)
-- EXEC xp_cmdshell 'mkdir C:\SQLBackups';

DECLARE @sql NVARCHAR(1000);
DECLARE @dbname SYSNAME;
DECLARE @filename NVARCHAR(500);
DECLARE @timestamp VARCHAR(20);

SET @timestamp = REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ':', '');
SET @timestamp = REPLACE(@timestamp, ' ', '_');

-- Backup each user database
DECLARE backup_cursor CURSOR FOR
    SELECT name
    FROM sys.databases
    WHERE name NOT IN ('tempdb')
      AND state_desc = 'ONLINE'
    ORDER BY name;

OPEN backup_cursor;
FETCH NEXT FROM backup_cursor INTO @dbname;

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @filename = @backup_path + @dbname + N'_Full_' + @timestamp + N'.bak';
    SET @sql = N'BACKUP DATABASE [' + @dbname + N']
    TO DISK = N''' + @filename + N'''
    WITH COMPRESSION,
         CHECKSUM,
         STATS = 10,
         FORMAT,
         INIT,
         NAME = N''' + @dbname + N' Full Backup'';';

    PRINT 'Backing up: ' + @dbname + ' -> ' + @filename;
    EXEC sp_executesql @sql;

    FETCH NEXT FROM backup_cursor INTO @dbname;
END;

CLOSE backup_cursor;
DEALLOCATE backup_cursor;
GO

-- Verify backups recorded in msdb
SELECT
    d.name AS database_name,
    bs.type AS backup_type,
    bs.backup_finish_date,
    CAST(bs.backup_size / 1024.0 / 1024.0 AS DECIMAL(10,2)) AS backup_size_mb,
    bs.is_compressed
FROM sys.databases d
LEFT JOIN msdb.dbo.backupset bs
    ON d.name = bs.database_name
    AND bs.backup_finish_date >= DATEADD(HOUR, -2, GETDATE())
ORDER BY d.name, bs.backup_finish_date DESC;
GO

10. Fix Full Recovery Databases Without Log Backups (Recommendation 8.2)

-- For developer databases where point-in-time recovery is NOT required,
-- switch from FULL to SIMPLE recovery model to prevent log file growth.
-- *** REVIEW EACH DATABASE BEFORE RUNNING — choose SIMPLE only if PITR is not needed. ***
-- After switching to SIMPLE, take a new full backup to establish a new backup chain.

USE master;
GO

-- Option A: Switch to SIMPLE recovery (recommended for developer/test databases
--           where point-in-time recovery is not required)

-- Uncomment the databases you want to switch to SIMPLE:

-- ALTER DATABASE [tpcc]       SET RECOVERY SIMPLE WITH NO_WAIT;
-- ALTER DATABASE [tpch]       SET RECOVERY SIMPLE WITH NO_WAIT;
-- ALTER DATABASE [tpch10]     SET RECOVERY SIMPLE WITH NO_WAIT;
-- ALTER DATABASE [CRM]        SET RECOVERY SIMPLE WITH NO_WAIT;
-- ALTER DATABASE [DigitsSolver] SET RECOVERY SIMPLE WITH NO_WAIT;
-- ALTER DATABASE [model]      SET RECOVERY SIMPLE WITH NO_WAIT;  -- system DB caution

-- After switching to SIMPLE, shrink the log to reclaim space (one-time operation only):
-- DBCC SHRINKFILE (N'', 64);  -- Shrink to 64 MB

-- Option B: If FULL recovery IS required, create a log backup job.
--           First take a full backup (run Script #9 above), then create log backups.
--           Example for tpch (has an existing full backup from 2025-11-22):

-- BACKUP LOG [tpch]
-- TO DISK = N'C:\SQLBackups\tpch_Log_' + REPLACE(REPLACE(CONVERT(VARCHAR,GETDATE(),120),'-',''),':','') + '.trn'
-- WITH COMPRESSION, CHECKSUM, STATS = 10;

-- Verify recovery models after changes
SELECT name, recovery_model_desc, log_reuse_wait_desc
FROM sys.databases
WHERE name NOT IN ('tempdb', 'master', 'msdb')
ORDER BY name;
GO

11. Audit SQL Logins and sa Account Status (Recommendation 6.3)

-- Audit all SQL Server logins, sysadmin members, and sa account status.
-- Review output for unexpected privileged accounts.

USE master;
GO

-- List all server logins with their roles and status
SELECT
    sp.name                     AS login_name,
    sp.type_desc                AS login_type,
    sp.is_disabled,
    sp.is_policy_checked,
    sp.is_expiration_checked,
    CASE WHEN srm.role_principal_id IS NOT NULL THEN 'YES' ELSE 'NO' END AS is_sysadmin,
    sp.create_date,
    sp.modify_date,
    sp.default_database_name
FROM sys.server_principals sp
LEFT JOIN sys.server_role_members srm
    ON sp.principal_id = srm.member_principal_id
   AND srm.role_principal_id = SUSER_ID('sysadmin')
WHERE sp.type IN ('S', 'U', 'G')  -- SQL, Windows user, Windows group
  AND sp.name NOT LIKE '##%'      -- Exclude internal accounts
ORDER BY is_sysadmin DESC, sp.name;
GO

-- Check sa account specifically
SELECT
    name,
    is_disabled,
    LOGINPROPERTY('sa', 'PasswordHash') AS has_password,
    LOGINPROPERTY('sa', 'BadPasswordCount') AS bad_password_count,
    LOGINPROPERTY('sa', 'IsLocked') AS is_locked
FROM sys.server_principals
WHERE name = 'sa';
GO

-- List all sysadmin members explicitly
SELECT
    ssp.name AS sysadmin_member,
    ssp.type_desc,
    ssp.is_disabled,
    ssp.create_date
FROM sys.server_role_members srm
JOIN sys.server_principals ssp ON srm.member_principal_id = ssp.principal_id
JOIN sys.server_principals srp ON srm.role_principal_id = srp.principal_id
WHERE srp.name = 'sysadmin'
ORDER BY ssp.name;
GO

12. Apply All Safe Server Configuration Changes in One Batch (Combined Script)

-- Combined script: Apply all safe, dynamic sp_configure recommendations at once.
-- No service restart required for these settings.
-- Settings included:
--   1. optimize for ad hoc workloads = 1
--   2. backup compression default    = 1
--   3. backup checksum default       = 1
--   4. blocked process threshold     = 5 seconds
-- Note: 'tempdb metadata memory-optimized' requires restart — see Script #4.

USE master;
GO

EXEC sp_configure 'show advanced options', 1;
RECONFIGURE WITH OVERRIDE;
GO

EXEC sp_configure 'optimize for ad hoc workloads', 1;
EXEC sp_configure 'backup compression default', 1;
EXEC sp_configure 'backup checksum default', 1;
EXEC sp_configure 'blocked process threshold (s)', 5;
GO

RECONFIGURE WITH OVERRIDE;
GO

-- Verify all changes
SELECT name, value, value_in_use, description
FROM sys.configurations
WHERE name IN (
    'optimize for ad hoc workloads',
    'backup compression default',
    'backup checksum default',
    'blocked process threshold (s)'
)
ORDER BY name;
GO

PRINT 'All configuration changes applied successfully at ' + CONVERT(VARCHAR, GETDATE(), 120);
GO
```