How to See Rowcounts and Execution Time for In-Flight Queries in SQL Server
I frequently need to see rowcounts and execution time for queries while they’re running. Maybe I’m troubleshooting a slow query …
Read MoreBy Kendra Little on • 7 min read
I’m a huge fan of SQL Server’s Query Store feature. Query Store collects query execution plans and aggregate query performance metrics, including wait stats. Having Query Store enabled makes troubleshooting performance issues such as bad parameter sniffing, much, much easier. Because Query Store is integrated into SQL Server itself, it also can catch query plans in a lightweight way that an external monitoring system will often miss.
When performance matters, it’s important to ensure that you’re managing Query Store so that Query Store cleanup does not run during high volume times. Query Store cleanup could slow your workload down significantly.

Cleanup isn’t easy. I know this from having needed to delete or update data in various circumstances over the years – it’s tough to clean things up safely without impacting performance.
Query Store has some issues with this currently as well.
If you collect wait stats in Query Store, Query Store size-based cleanup of wait stats runs a query:
DELETE
pws
FROM sys.plan_persist_wait_stats AS pws
WHERE pws.plan_id IN
(
SELECT
pp.plan_id
FROM sys.plan_persist_plan AS pp
WHERE pp.query_id = @query_id
);
I can produce this behavior/impact in a test environment with a synchronous Availability Group setup using Ostress.exe, after first building up a volume of data in Query Store.
I have not been able to produce similar impacts from other parts of Query Store cleanup, only wait stats cleanup, but it might be that they exist and my testing simply didn’t uncover them. Better safe than sorry.
If you have a performance critical database and you want to ensure this doesn’t happen, you don’t have to collect wait statistics in Query Store.
I find the wait stats in Query Store to be occasionally useful only. They are aggregate wait stats, so they can give a general idea for simple issues like whether or not a query often waits on lock waits, but they aren’t super granular. If you do have an external monitoring system that is collecting wait stats, and if it allows you to correlate those wait stats to queries, you might simply decide not to collect wait stats in Query Store.
Notes:
Query Store has two types of cleanup: time based and size based.
If performance is critical, you should tune your query store so that only time-based cleanup runs.
Things to know about size based cleanup:
You may want to allow Query Store some more room in MAX_STORAGE_SIZE_MB so that sized-based cleanup doesn’t kick in. Be aware that you shouldn’t go completely wild with this – as the fantastic Erin Stellato mentions in Query Store Best Practices: MAX_STORAGE_SIZE_MB should be “set to 10GB at the absolute max, something less ideally”
Erin recommends a custom capture policy to help if you need to reduce the amount of space that Query Store data takes up.
Erin mentions in Remove Data from Query Store that…
ideally, size-based cleanup never kicks in…. This algorithm is not efficient, and it runs single-threaded. It looks for queries that are infrequently executed/less important and deletes those, one by one, until the size is less than 80% of MAX_STORAGE_SIZE_MB. Avoid this type of cleanup if at all possible.
My testing shows this to be very good advice.
To monitor size based cleanup, you can trace the query_store_size_retention_cleanup_started and query_store_size_retention_cleanup_finished Extended Events. Read more in Zikato’s answer on StackOverflow.
Josh Darnell has written an excellent post on Timing of the Automatic Query Store Purge. I won’t rehash his whole post here– go read it!
The most important basic bits are:
That means that if you happen to have a failover in the middle of the day, you may end up with time-based cleanup running in the middle of the day. Not ideal. Depending on your tolerance of cleanup running at a high volume time, this might be worth a planned failover at a low volume time.
As much as I don’t love that, I still find Query Store to be useful enough in general to deal with that.
To monitor time based cleanup, you can trace two Extended Events: query_store_db_cleanup__started and query_store_db_cleanup__finished. Only time-based cleanup events are captured in these events.
There are a few stored procedures you can do to add custom cleanup jobs to run on schedule if you like. Erin Stellato give examples of them in ‘Remove Data from Query Store’:
EXECUTE sys.sp_query_store_remove_query
@query_id = ZZZ;
EXECUTE sys.sp_query_store_remove_plan
@plan_id = YYY;
EXECUTE sys.sp_query_store_reset_exec_stats
@plan_id = YYY;
The following things would be super helpful:
And one correction… I had suggested:
Increase visibility of when size-based cleanup runs. I would really prefer for this to be logged in a DMV rather than an extended event, as that’s easier to get into monitoring systems, but I’ll take whatever I can get.
Update: this already exists as an Extended Event. See Zikato’s answer on using query_store_size_retention_cleanup_started and query_store_size_retention_cleanup_finished on StackOverflow.
Happy performance tuning, and please remember to tip your Query Store (by not allowing size-based cleanup to run).
Erin is super helpful, so smart, and just one of the best folks around. All of her posts on Query Store are incredibly helpful, just search “Erin Stellato Query Store” when you have a question :) If you work with Erin, please tell her that her awesomeness is widely loved.
Thanks also to Josh Darnell for his excellent posts on Query Store Cleanup. This was also super helpful to me. And thanks to Tomáš Zíka (Zikato) for his answer detailing how to trace size-based cleanup.
Copyright (c) 2025, Catalyze SQL, LLC; all rights reserved. Opinions expressed on this site are solely those of Kendra Little of Catalyze SQL, LLC. Content policy: Short excerpts of blog posts (3 sentences) may be republished, but longer excerpts and artwork cannot be shared without explicit permission.