When your index rebuilds are stuck at 0% (but lying to you)

official documentation showing the percent_complete column does not include index rebuilds, but rather only index reorgs

Ever had a situation where you’re rebuilding a large index but when you check sp_whoisactive, you see 0% complete … and you know the system is just lying to you?

We recently had a scenario where we were rebuilding a large index for a customer over a long weekend. We were monitoring closely, as this has caused production issues in the past. After 2.5 hours, we did not see any progress on the rebuild.

For full visibility, this rebuild was being performed by the Ola Hallengren index optimize stored procedure and was using this command (anonymized):

ALTER INDEX [IndexName] ON [dbo].[TableName] REBUILD WITH (SORT_IN_TEMPDB = OFF, ONLINE = ON, MAXDOP = 8, FILLFACTOR = 100, RESUMABLE = OFF)

This is what we see in sp_whoisactive, we were not blocked, we were not waiting on any resources but our % completion is at 0 still.

 

Are We Making Progress?

We can go directly to the source if we choose and query sys.dm_exec_requests to check our progress from there.

SELECT

r.session_id,

r.status,

r.command,

r.blocking_session_id,

r.wait_type,

r.wait_time / 1000.0 AS wait_seconds,

r.wait_resource,

r.total_elapsed_time / 1000.0 AS elapsed_seconds,

r.percent_complete

FROM sys.dm_exec_requests AS r

WHERE r.session_id = /*your spid*/;

However we see 0% here too:

The reason is actually interesting. The official documentation does state that the percent_complete column does not include index rebuilds, but rather only index reorgs (and other not directly related commands).

So that explains our predicament here: This DMV just doesn’t provide data for rebuilds like ours. Because of this we’re going to have to look at different options.

Pursuing Options

Luckily, we’re on a new enough version of SQL Server that we have lightweight query profiling enabled:

SELECT name, value, value_for_secondary

FROM sys.database_scoped_configurations

WHERE name = 'LIGHTWEIGHT_QUERY_PROFILING';

Because of this, we can use sys.dm_exec_query_profiles to see how far along the query believes itself to be.

SELECT

qp.node_id,

qp.physical_operator_name,

qp.row_count,

qp.estimate_row_count,

CAST(qp.row_count AS DECIMAL(18,2))

/ NULLIF(qp.estimate_row_count, 0) * 100 AS pct_complete_by_rows,

qp.elapsed_time_ms / 1000.0 AS elapsed_seconds,

qp.cpu_time_ms / 1000.0 AS cpu_seconds

FROM sys.dm_exec_query_profiles AS qp

WHERE qp.session_id = /*your spid here */

ORDER BY qp.node_id;
From the results, we can see that we’re still actually reading our data from the source table:

As we’re running with a MAXDOP of 8, we can see the separate threads here and their individual progress.

It’s worth making clear that these are estimated row counts, not actuals.  They are only as good as your statistics on these tables are. However, when I ran this again a few minutes later, we can see that our parallel threads are still making progress and not stuck at 0% as we were, at first, lead to believe:

Notice that a couple of threads are over 100% completion. That’s due to statistics that aren’t quite right and the actual row counts are above that.

We can make this query a little more concise if we choose:

SELECT

qp.node_id,

qp.physical_operator_name,

SUM(qp.row_count) AS total_rows_processed,

SUM(qp.estimate_row_count) AS total_estimated_rows,

CAST(SUM(qp.row_count) AS DECIMAL(18,2))

/ NULLIF(SUM(qp.estimate_row_count), 0) * 100 AS pct_complete,

SUM(qp.elapsed_time_ms) / 1000.0 AS elapsed_seconds,

SUM(qp.cpu_time_ms) / 1000.0 AS cpu_seconds

FROM sys.dm_exec_query_profiles AS qp

WHERE qp.session_id = 468

GROUP BY qp.node_id, qp.physical_operator_name

ORDER BY qp.node_id;

</ br>

Lies, Damn Lies, and Statistics

That tells us that we’re 94% complete with our index scan at this point and we can continue to monitor from here. What’s interesting for this scenario — and I need to test this further — is that the scans took all of the time for this query. Once those had finished, it completed almost instantly. 0%, my foot!
I hope this helps those of you sitting there looking at a blank completion figure and having a low-level anxiety attack.

</ br>


 

If SQL Server is doing something you can’t decipher, we’d love to help! Put our 90+ years of combined SQL Server experience to work for you.

Please share this

Related Articles