Erik cries when SSMS lies

My SQL Server friendo Mr. Erik C. Darling was recently telling me about some work he did getting batch mode on paging queries. This sounded a bit odd to me because paging queries make me think of small seeks of rows against finely curated nonclustered rowstore indexes, so I asked him for a link to his blog post about it. He grumpily refused and told me to find the link myself, which I eventually did.

High End Machine Performance

Erik’s first attempt used OFFSET/FETCH and resulted in a row mode query:

SQL Server Query Plan

The clustered index scan makes this a bit of a sad paging query. In Erik’s defense, there’s a whole host of real world reasons as to why you wouldn’t be able to make the perfect nonclustered index for your paging query:

  • End users may choose to sort on many different columns and you can’t index them all
  • A key member of your Index Approval Committee is on vacation
  • You already have more indexes on the table than your number of fingers
  • You’re working with third party software which does not allow you to create custom indexes

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. The red lines illustrate the problem perfectly and I won’t be elaborating further:

Erik’s second attempt uses ROW_NUMBER() and he achieves a plan with some batch mode operators using BMOR (batch mode on row store):

SQL Server Query Plan

The parallel batch mode sort works just fine here in that the single thread output property isn’t an issue. The parent operator is a batch mode window aggregate, but even if it wasn’t, the grandparent is a gather streams operator so the rows would end up on one thread anyway. Actual time statistics accounting works differently for batch mode operators: each batch mode operator only tracks its own work. In terms of real work done by the query, the scan clocks in at 1.1022 seconds and the sort clocks in at 0.892 seconds. This is quite similar to the first attempt. It could be argued that the batch mode sort is more efficient than the row mode top N sort, but I’d call it a wash considering the unpredictable rowstore to batch mode conversion overhead (which does seem to be small for this table).

Low End Machine Performance

I tested on my local machine with 64 GB of RAM which is less than Erik’s laptop. My clustered index scans took significantly longer than his, but as usual, there’s a lot to learn from low end machine performance. Let’s go back to the first reason as to why the table might not be indexed well for this particular query:

End users may choose to sort on many different columns and you can’t index them all

Microsoft presents a standard solution for this scenario: the humble nonclustered columnstore index. This will be great for my low end machine because I’ll be able to fit the new NCCI in memory. For those following along at home on their own low end machines, I created the index on every column except the Body column in a very carefree fashion:

CREATE NONCLUSTERED COLUMNSTORE INDEX ncci ON posts (
  Id
, AcceptedAnswerId
, AnswerCount
, ClosedDate
, CommentCount
, CommunityOwnedDate
, CreationDate
, FavoriteCount
, LastActivityDate
, LastEditDate
, LastEditorDisplayName
, LastEditorUserId
, OwnerUserId
, ParentId
, PostTypeId
, Score
, Tags
, Title
, ViewCount
) WITH (MAXDOP = 1)

I ran the OFFSET/FETCH query on my low end machine with MAXDOP 4 and it only took 430 CPU ms and 130 ms of elapsed time:

That’s a huge improvement compared to the 15-20 second runtime I was experiencing earlier. Interestingly, the second query (the ROW_NUMBER() approach) sticks with the parallel batch mode sort and performs significantly worse in comparison:

The key difference here is the batch mode Top N sort in the first query. Remember that the query compile process for BMOR is different than what you get when compiling in the presence of a glorious columnstore index. You can get the improved batch mode top N sort by also doing a fake join to an empty CCI table. Serious batch mode connoisseurs should be mindful of the compile differences as they seek to gain the greatest performance benefit possible from batch mode.

Final Thoughts

Friends don’t let friends be lied to by SSMS. Thanks for reading!

SQL Server Management Studio Should Add Filters When You Get Execution Plans

Have You Heard The One…


Whenever I’m tuning a long stored procedure, I use sp_HumanEvents to grab query plans and other details about what’s going on.

The thing is… It should be a lot easier than that. Unfortunately, when you tell SSMS that you want to get actual execution plans, it gives you absolutely everything.

For code that loops or has a lot of tiny queries that run leading up to more painful queries. All that is a slog, and can result in SSMS becoming unresponsive or crashing.

It’s be really cool if hitting the Actual Execution Plan button filter out some stuff so you’re not collecting everything.

It could even use the same GUI style as Extended Events.

SQL Server Extended Events
in england

Granted, not all the ones pictured here would make sense, but metrics like CPU and duration would be helpful to keep noisy query plans out of the picture.

Thanks for reading!

Going Further


If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that, and need to solve database performance problems quickly. You can also get a quick, low cost health check with no phone time required.

Make ADS An Optional Install Alongside SSMS

Update Update!


Starting with SSMS 20, ADS is no longer bundled together with it.

From: Upcoming changes for SQL Server Management Studio (SSMS) – Part 3:

For SSMS 20 we have removed Azure Data Studio from the installation.  In addition to being a highly voted item (Make ADS An Optional Install Alongside SSMS · Community (azure.com)), this aligns with the future extension work for SSMS 21 and we decided to make the change in the current release.

I’m quite happy to be aligned with future extension work for SSMS 21 🥰

Update!


Starting with SSMS 18.8 officially, but available in SSMS 18.7 as well, if you install via command line, you can use the following switch to avoid installing Azure Data Studio (ADS).

SSMS-Setup-ENU.exe /Passive DoNotInstallAzureDataStudio=1

Odd Couple


SSMS 18.7 was released, with an announcement that whenever you install SSMS from here on out, you’d also be installing Azure Data Studio, along with whatever dependencies exist in there. Right now, there’s a short list, but that might change so I’m not going to get into it.

It’s an odd choice, and a bit forced. Sort of like whenever you go to update Java and it wants to install three toolbars and something to clean out your internet cache. But at least Oracle has the decency to ask first.

I’ve opened a UserVoice item to let ADS be an optional install, rather than forced.

The thing is, they’re tools for totally different people. If you look at the feature comparison sheet for ADS and SSMS, you can see what I mean.

Don’t You Read The Slides?


Mr. O has a great slide about the different kinds of DBAs you might meet in the world. If you pair that up with the features that are available in each tool, you can see where each one pretty neatly fits into different roles and the way they’d work.

If you need to work cross-platform, deal with source code, big data clusters, or more developer-related tasks, ADS is for you.

Go get it! After all, it’s still a standalone download, too ???

If you’re working with query plans in depth, AGs, Query Store, or about a dozen other tasks that are more DBA-focused, you still have to use SSMS, and it doesn’t make much sense to switch back and forth unless you specifically need something only ADS does.

Likewise, it doesn’t make sense to switch between ADS and SSMS if you don’t use any of the SSMS-specific functionality.

There’s totally part of the crowd that might need both. I get that, too. But bundling them together is sort of like selling someone a six pack of beer, where three of them are non-alcoholic.

I’ve nothing against ADS. I think it fits well into very specific workflows, just not enough to force everyone who needs SSMS to also install it.

Make ADS An Optional Install Alongside SSMS


From the UserVoice issue:

Starting with SSMS 18.7, Azure Data Studio is being automatically installed alongside SSMS with no option to not install it. ADS is still available as a standalone install, though.

I’d like a way to make the install optional for people who don’t need any ADS functionality.

Particularly for admins putting SSMS on their SQL Server for whom additional unknown dependencies might not be tolerable to security teams, not having to remember to uninstall additional items every time they update SSMS would be helpful. Even with an automated deployment, it requires an installation and then multiple uninstaller runs.

On top of that, ADS is updated monthly, and SSMS has a less frequent release cadence. That leaves most people juggling two installers anyway, or only updating ADS when they update SSMS. That seems an odd choice, especially given the lack of reciprocal bundling.

Thanks for reading!

Going Further


If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that and need to solve performance problems quickly.