SLEEP_TASK waits on single-threaded UPDATE that does not generate an in-flight plan, how are these waits possible?
1
vote
0
answers
92
views
Yesterday, I witnesses a running query in
With this database dropping and creating script, I can get an actual execution plan of identical shape.
sp_WhoIsActive
that I could not explain. It had the following properties:
* It ran in a nested transaction. The first transaction bulk inserts into a temp table that is later given a unique clustered index. The second runs an UPDATE
against a system-versioned table.
* The UPDATE
was running for hours despite usually taking less than seconds. 5 minutes at most.
* There were multiple calls to this UPDATE
in different sessions, all being blocked by one of them.
* sp_WhoIsActive
revealed that:
* The query has no in-flight execution plan (@get_plans = 2
)
* **The block leader is almost always blocked on "SLEEP_TASK", but sometimes it isn't blocked at all. I recall that it seems to stay blocked on this for about 4ms.**
* The query was still doing work, only reads as far as I could tell, but incredible slowly (from @delta_interval = 10
)
* My guess is that the query waits on SLEEP_TASK for some set amount of time, does one read, and then goes back to sleep.
* All of the reads were logical, not physical.
* The block leading query had so far done millions of reads, but the blocked queries had only done tens of thousands
* The query was single-threaded (@get_task_info = 2
)
* open_tran_count
was 3
* I cannot share the XML showing the locks, but I find it interesting that it shows that the block leader shows:
* S lock on "DATABASE.ENCRYPTION_SCAN"
* Sch-S lock on "METADATA.PLAN_GUIDE_HASH"
* Lots of locks on both the table and its history table
* tempdb locks all presumably taken by the transaction populating the temp table.
* For the blocked queries, the lock XML showed that they were all waiting on an IX lock on the clustered index of the history table. This index is partitioned and not unique. The history table has no other indexes.
* The main table has only a primary key. It is not partitioned.
* I have confirmed that the history table is free of corruption.
The text of the query this, but with the names changed.
UPDATE
MyTable
SET
MyTable.FloatCol = TempTable.FloatCol,
MyTable.Date = TempTable.Date
FROM
#TempTableWithUniqueClusteredIndex AS TempTable
JOIN
TemporalTableWithJustAPrimaryKey AS MyTable
ON
MyTable.PrimaryKeyInt = TempTable.PrimaryKeyInt;
Query Store holds an estimated plan for this query. It is of this shape.

SET STATISTICS XML OFF;
IF @@TRANCOUNT > 0
BEGIN
ROLLBACK;
END;
-- =========================================
-- 1. Drop/Create sample DB and switch context
-- =========================================
USE master;
GO
ALTER DATABASE SampleDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
DROP DATABASE IF EXISTS SampleDB;
GO
CREATE DATABASE SampleDB;
GO
USE SampleDB;
GO
-- =========================================
-- 2. Partition function & scheme for history
-- (partitioning by ValidFrom date/time)
-- =========================================
CREATE PARTITION FUNCTION PF_ValidFrom (DATETIME2)
AS RANGE LEFT FOR VALUES
('2015-01-01','2020-01-01','2025-01-01');
GO
CREATE PARTITION SCHEME PS_ValidFrom
AS PARTITION PF_ValidFrom
ALL TO ([PRIMARY]);
GO
-- =========================================
-- 3. Pre-create history table on scheme
-- =========================================
CREATE TABLE dbo.MainTableHistory
(
PrimaryKeyInt INT NOT NULL,
FloatCol FLOAT NOT NULL,
[Date] DATE NOT NULL,
ValidFrom DATETIME2 NOT NULL,
ValidTo DATETIME2 NOT NULL
)
ON PS_ValidFrom (ValidFrom);
GO
-- Partitioned, non-unique clustered index on history
CREATE CLUSTERED INDEX CX_MainTableHistory
ON dbo.MainTableHistory(PrimaryKeyInt, ValidFrom)
ON PS_ValidFrom (ValidFrom);
GO
-- =========================================
-- 4. Create main temporal table (unpartitioned)
-- with a DATE column and system-period cols
-- =========================================
CREATE TABLE dbo.TemporalTableWithJustAPrimaryKey
(
PrimaryKeyInt INT NOT NULL
CONSTRAINT PK_TemporalTable PRIMARY KEY,
FloatCol FLOAT NOT NULL,
[Date] DATE NOT NULL,
ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
ValidTo DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
ON [PRIMARY];
GO
-- =========================================
-- 5. Seed MainTable with 1,000 rows
-- =========================================
INSERT INTO dbo.TemporalTableWithJustAPrimaryKey (PrimaryKeyInt, FloatCol, [Date])
SELECT TOP (1000)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)),
RAND(CHECKSUM(NEWID())) * 100, -- random float
DATEADD(day, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) % 365, '2020-01-01')
FROM sys.all_columns a
CROSS JOIN sys.all_columns b;
GO
-- =========================================
-- 6. Turn on system versioning pointing at our history
-- =========================================
ALTER TABLE dbo.TemporalTableWithJustAPrimaryKey
SET (SYSTEM_VERSIONING = ON
(HISTORY_TABLE = dbo.MainTableHistory
,DATA_CONSISTENCY_CHECK = ON));
GO
-- =========================================
-- 7. Simulate nested transactions:
-- =========================================
BEGIN TRAN
CREATE TABLE #TempTableWithUniqueClusteredIndex
(
PrimaryKeyInt INT NOT NULL,
FloatCol FLOAT NOT NULL,
[Date] DATE NOT NULL
);
INSERT INTO #TempTableWithUniqueClusteredIndex (PrimaryKeyInt, FloatCol, [Date])
SELECT TOP (50)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)),
RAND(CHECKSUM(NEWID())) * 100,
DATEADD(day, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) % 365, '2021-01-01')
FROM sys.all_columns a
CROSS JOIN sys.all_columns b;
CREATE UNIQUE CLUSTERED INDEX CX_Temp_UC
ON #TempTableWithUniqueClusteredIndex(PrimaryKeyInt);
BEGIN TRAN
SET STATISTICS XML ON;
UPDATE
MyTable
SET
MyTable.FloatCol = TempTable.FloatCol,
MyTable.Date = TempTable.Date
FROM
#TempTableWithUniqueClusteredIndex AS TempTable
JOIN
TemporalTableWithJustAPrimaryKey AS MyTable
ON
MyTable.PrimaryKeyInt = TempTable.PrimaryKeyInt;
ROLLBACK;
My question is this: **does anything that I have said above explain these SLEEP_TASK waits?** To [my knowledge](https://www.sqlskills.com/help/waits/sleep_task/) , such waits should be very rare on single-threaded queries.
Asked by J. Mini
(1225 rep)
Jun 29, 2025, 01:02 AM
Last activity: Jul 2, 2025, 07:27 PM
Last activity: Jul 2, 2025, 07:27 PM