Press "Enter" to skip to content

Category: Query Tuning

Indexes and COUNT() in SQL Server

Louis Davidson does some testing:

A few weeks ago, there was a LinkedIn post (I can’t find it anymore) that covered something about how indexes were used by COUNT in SQL. I think it may have been based on SQL Server, but I am not sure (it is rare that one of the SQL posts on LinkedIn mentions a platform). At the time, I went and tried a few of the mentioned cases and realized this was an interesting question: how does the COUNT aggregate use indexes when you use various different expressions.

Louis has a series of test cases and I got most of them right, though I wasn’t sure about one particular optimization.

Leave a Comment

Parameter Sensitivity Training

Erik Darling finally gets HR involved. The sad and/or clever part is that I wrote that line before Erik made the joke.

This is Part 1 in a set of videos covering Erik’s talk for PASS Data Community Summit in 2025. As is usual, Erik’s videos are worth watching even though he doesn’t give me even one paragraph that I can copy and include as a graf here, meaning that I need to type in more in order to make it so that any RSS feed reader connected to Curated SQL doesn’t panic and force you to open the post because it’s too short, and thus causing me to write even longer run-on sentences than I normally would write, though I typically indulge myself in run-on sentences so the blame isn’t 100% on Erik; in short, Erik allows me to use semi-colons more often, and I appreciate it.

2 Comments

Diagnosing DirectQuery Performance Woes

Chris Webb digs into one type of DirectQuery performance slowdown:

One very common cause of Power BI performance problems is having a table with a large number of rows on your report. It’s a problem I wrote about here, and while I used an Import mode for my example in that post I also mentioned that this can be an even bigger problem in DirectQuery mode: while the DAX query for the table visual might have a TOPN filter that asks for 502 rows, the query going back to the DirectQuery data source (usually a SQL query) may not have that filter applied and could return a much larger number of rows, which could then take a long time for Power BI to read. I wrote about this in more detail here and showed how you can diagnose the problem in Performance Analyzer by looking at the Execute DirectQuery event and ActualQueryDuration, RowsRead and DataReadDuration metrics. But now I have a custom visual to display Performance Analyzer export data, what does this look like? Also, what can Execution Metrics tell us?

Read on to learn more.

Leave a Comment

Query Estimates and Tooling in Oracle

David Fitzjarrell lays out a comparison:

Depending upon which tool is used query plans can change. There are two provided by Oracle, SQL*Plus and SQL Developer, and how they treat bind variables can alter execution plans. Let’s look into that and see what may be the cause.

SQL*Plus has been around for quite a while and is a very mature product. SQL Developer also has a long history, not quire as long as SQL*Plus but is well beyond the early phases of development. Both are excellent tools, returning reliable and repeatable results, but SQL Developer may take some liberties SQL*Plus doesn’t, especially where bind variables are involved. SQL*Plus and PL/SQL allow the developer to define data types for bind variables, and will pass those values through unchanged. SQL Developer, however, appears to pass such values using a character data type regardless whether the value is a string or numeric, allowing Oracle to ‘decide’ how to optimize the query. This can produce sometimes ‘unexplained’ results with estimates and execution plans.

Read on for an example in which the choice of tool can add a considerable percentage to the expected length of the query. The tricky part here is that this doesn’t mean the query actually takes longer, but that expectations will differ.

Leave a Comment

The Impact of Sorting and Filters on Pagination

Aaron Bertrand continues digging into SQL Server pagination performance:

In my previous tip, Pagination Performance in SQL Server, I showed how to make SQL pagination more predictable – turning O(n) into O(1). I materialized and cached row numbers to page through instead of calculating them on every request. It wasn’t the whole story, though; real pagination queries rarely get to sort without filtering. Users always want more control, and filtering can threaten that predictability.

Read on for examples of how to handle a few different scenarios.

Comments closed

Consistent Pagination Performance in SQL Server

Aaron Bertrand takes life one page at a time:

Many web applications and APIs implement pagination to control how much data is returned or displayed. Many paging solutions suffer from the linear scaling problem (often referred to as O(n)), meaning the amount of work increases as you get into higher page numbers. If a user has ever clicked “next page” or “last page” and your CPUs caught on fire, you may have been a victim of linear scaling. Are there any creative solutions that will achieve constant-time performance (O(1))?

Aaron’s answer is interesting, particularly if you’re able to define the valid set of filters. At a prior job, I was responsible for filtering of arbitrary combinations of 30+ different columns across multiple dimensions and a fact table in a warehouse. That was a royal pain. The best we could do was run the query once, using ROW_NUMBER() to capture the sort order, and then store that ordering in a specialized table with an identifier token that was a hash of the incoming session info, and cache that data for a pre-set amount of time—which, if I remember correctly, was 5 minutes. Somewhat similar to what Aaron shows but much more ephemeral and it caused the first load to be consistently slower while making subsequent paging activities much faster.

Comments closed

When IQP Features Make Things Worse

Rebecca Lewis has a two-parter. First up is a post covering the guard rails available in IQP:

When Microsoft introduced Intelligent Query Processing in SQL Server 2019 and expanded it in SQL Server 2022 and 2025, the message was simple: upgrade, enable the right compatibility level, and the optimizer will quietly make your queries faster. Features like batch mode on rowstore, memory grant feedback, scalar UDF inlining, and parameter-sensitive plan (PSP) optimization all promise “automatic performance.”

But buried in Microsoft’s documentation is a reality worth understanding: Some IQP features can reduce or discontinue feedback when performance becomes unstable. This is intentional. IQP includes guard rails—safety mechanisms that change or stop certain feedback behaviors if they prove counterproductive.

Part two tells us how to figure out if an IQP feature got the works:

Memory Grant Feedback was introduced in SQL Server 2019 and enhanced in SQL Server 2022+. Microsoft documents several plan attributes that reveal how the engine adjusted or suspended feedback. These attributes appear under the MemoryGrantInfo node in the execution plan.

And stay tuned for part three.

Comments closed

Row Counts and Execution Time for Active SQL Server Queries

Kendra Little wants to know what’s happening right now with this query:

I frequently need to see rowcounts and execution time for queries while they’re running. Maybe I’m troubleshooting a slow query that’s still executing, or I want to understand which operators are causing the slowdown before the query completes.

Last week at the PASS Summit I learned some little nuances about how this works that I’d missed.

Click through to learn what Kendra learned (and now what I learned).

Comments closed

Functions and WHERE Clauses

Brent Ozar digs into some of the nuance:

SQL Server brought back 1856 of an estimated 1856 rows. So far, so good. But what happens when we start running functions on the parameter we’re searching for, like if it’s a parameter that we need to clean up. How will this affect our estimated number of rows:

Your knee-jerk reaction is probably to say, “FUNCTIONS BAD!” especially given that this is a case-insensitive database. But let’s test that hypothesis across time, across different database compatibility levels:

Brent give some of the nuance behind this. Which, in fairness, aligns with what some of the best performance tuning practitioners have frequently stated. But in contra-fairness, Brent shows how that advice should also change depending on the version of SQL Server, and how the first few versions of SQL Server after the no-longer-new cardinality estimator behaved radically differently from pre-2014 or post-2019.

Comments closed

Parallel Performance and SSMS Outputs

Joe Obbish looks at some execution plans:

Getting back to the query, it doesn’t look that offensive to me. The row mode sort is a parallel top N sort and the overall number of rows to return is low, so each thread can independently sort its rows and return 1000 locally sorted rows to the parent operator. This is about as good as it gets with parallel row mode sorting. This is a row mode only query so the operator times that you see are the sum of that operator’s work and its children. In terms of real work done by the query, the scan clocks in at 1.168 seconds and the sort clocks in at 0.84 seconds. The final accounting at the end by the parent Parallelism (Gather Streams) is misleading at best and an outright LIE at worst. There wasn’t 4 seconds of work done by this query. There was only 2 seconds. 

Joe looks at two separate things in this post: first, a way of trying to optimize OFFSET/FETCH style paging queries; and second, how the gather streams parallel operator can report wrong information.

Comments closed