SQL Server – Query Store Query Hints

Query hints is a new feature introduced in SQL Server 2022, please go over the following simulation to understand this great feature.

// create the following dummy database with the below t-sql code:

CREATE DATABASE RethinkRecompileDemo;

ALTER DATABASE RethinkRecompileDemo SET RECOVERY SIMPLE;

GO

USE RethinkRecompileDemo;

GO

CREATE TABLE dbo.SalesOrders

(

    SalesOrderId INT IDENTITY(1, 1) NOT NULL,

    OrderDate DATETIME NOT NULL,

    CustomerId INT NOT NULL,

    SalesPersonId INT NOT NULL,

    TotalAmount DECIMAL(10, 2) NOT NULL,

    OrderStatus VARCHAR(50) NOT NULL,

    CreateDate DATETIME NOT NULL

        DEFAULT GETDATE(),

    CONSTRAINT PK_SalesOrders_Id

        PRIMARY KEY CLUSTERED (SalesOrderId)

);

GO

;WITH cteN (Number)

 AS (SELECT TOP 3000000

         ROW_NUMBER() OVER (ORDER BY (SELECT NULL))

     FROM sys.all_columns AS s1

         CROSS JOIN sys.all_columns AS s2

    )

INSERT INTO dbo.SalesOrders

(

    OrderDate,

    CustomerId,

    SalesPersonId,

    TotalAmount,

    OrderStatus

)

SELECT DATEADD(DAY, RAND(CHECKSUM(NEWID())) * (1 + 1095), ‘2020-01-01’) AS OrderDate,

       ABS(CHECKSUM(NEWID()) % 5000) + 1 AS CustomerId,

       CASE

           WHEN RAND(CHECKSUM(NEWID())) < 0.75 THEN

               ABS(CHECKSUM(NEWID()) % 50) + 1

           ELSE

               ABS(CHECKSUM(NEWID()) % 450) + 51

       END AS SalesPersonId,

       ABS(CHECKSUM(NEWID()) % 500) + 150 AS TotalAmount,

       CASE

           WHEN RAND(CHECKSUM(NEWID())) < 0.10 THEN

               ‘New’

           WHEN RAND(CHECKSUM(NEWID())) < 0.20 THEN

               ‘In process’

           ELSE

               ‘Shipped’

       END AS OrderStatus

FROM cteN n;

GO

CREATE NONCLUSTERED INDEX [IX_OrderDate+SalesPersonId+TotalAmount]

ON [dbo].[SalesOrders] ([OrderDate])

INCLUDE

(

    [SalesPersonId],

    [TotalAmount]

);

GO

CHECKPOINT;

GO

// I have altered the query store setting to capture it quickly….every 1 minute

USE [master]

GO

ALTER DATABASE [RethinkRecompileDemo] SET QUERY_STORE (OPERATION_MODE = READ_WRITE, DATA_FLUSH_INTERVAL_SECONDS = 60, INTERVAL_LENGTH_MINUTES = 1, QUERY_CAPTURE_MODE = ALL)

GO

// create a procedure under the database:

use [RethinkRecompileDemo]

GO

CREATE OR ALTER PROCEDURE dbo.proc1

    @OrderStatus varchar(50)

AS

SELECT *

FROM dbo.SalesOrders

WHERE OrderStatus=@OrderStatus

GO

// execute the procedure multiple times with different values as shown below

use [RethinkRecompileDemo]

GO

EXECUTE dbo.proc1

@OrderStatus=”Shipped”

GO

EXECUTE dbo.proc1

@OrderStatus=”New”

GO

EXECUTE dbo.proc1

@OrderStatus=”In process”

GO

// enable the execution plan generation in SQL Server Management Studio, a parameter list is being displayed and as expected its using the same @OrderStatus value passed  “Shipped” even with different queries

// I will explore now the query hint feature:

To find the query id:

use[RethinkRecompileDemo]

GO

SELECT q.query_id, qt.query_sql_text

FROM sys.query_store_query_text qt

INNER JOIN sys.query_store_query q ON

    qt.query_text_id = q.query_text_id

WHERE query_sql_text like N’%OrderStatus=%’;

GO

// Will enable the RECOMPILE hint option on the query through the query store:

use[RethinkRecompileDemo]

GO

EXEC sys.sp_query_store_set_hints @query_id= 129, @query_hints = N’OPTION(RECOMPILE)’

Query for verification that the hint is in effect:

use[RethinkRecompileDemo]

GO

SELECT query_hint_id, query_id, query_hint_text, last_query_hint_failure_reason, last_query_hint_failure_reason_desc, query_hint_failure_count, source, source_desc

FROM sys.query_store_query_hints

WHERE query_id = 129;

Re-execute the three procedures again and as shown below of the execution plan, the hint is applied successfully to overcome “parameter sniffing” problem and “Parameter List” is not being displayed in the properties windows on the right side:

In the database query store…view “Top Resource Consuming Queries” and view the executed query properties:

Query hint option is displayed:

SQL Server 2025 TEMPDB Resource Governor (Optimizing TEMPDB Usage)

For the sake of illustration I will set maximum amount of TEMPDB usage is set at 200MB (of course in real world this is NOT a parctical value at all !! I am setting it to quickly reach the maximum configured resource governer value)

Will create a new custom workload and will call it limit_tempdb:

CREATE WORKLOAD GROUP limit_tempdb

WITH (

     GROUP_MAX_TEMPDB_DATA_MB = 200

     )

USING [default];

ALTER RESOURCE GOVERNOR RECONFIGURE;

You can check the current configured workloads at instance-level:

SELECT group_id,

       name,

       group_max_tempdb_data_mb,

       group_max_tempdb_data_percent

FROM sys.resource_governor_workload_groups;

Then, I will create a classifier function:

USE master;

GO

CREATE FUNCTION dbo.RG_UserNameClassifier()

RETURNS sysname

WITH SCHEMABINDING

AS

BEGIN

    IF (SUSER_SNAME() = ‘test’)

BEGIN

        RETURN ‘limit_tempdb’; 

END

    RETURN ‘default’;

END;

GO

ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = dbo.rg_classifier);

ALTER RESOURCE GOVERNOR RECONFIGURE;

I will then connect using “test” account using SQL Server Management Studio:

// I will create a dummy temporary table that will be created in TEMPDB database and populate it with dummy data intensively :

create table #test (Col1 varchar(80));

GO

insert into #test values (‘HELLO EMAD, HOW ARE YOU’)

GO 300000000

when the utilization reaches 200MB the following error will be thrown:

Msg 1138, Level 17, State 1, Procedure sp_checktempdb, Line 132 [Batch Start Line 0]

Could not allocate a new page for database ‘tempdb’ because that would exceed the limit set for workload group ‘limit_tempdb’, group_id 256