Press "Enter" to skip to content

Category: Indexing

Querying JSON Quickly in SQL Server 2025

Brent Ozar follows up on yesterday’s post:

SQL Server 2025 and .NET 10 bring several new improvements to storing JSON natively in the database and querying it quickly.

On the SQL Server 2025 side, the two big ones are the new native JSON indexes and the new JSON_CONTAINS function. Let’s see their improvements in action. On the .NET 10 side, EF 10 not only supports the new JSON data type, but on databases of compatibility level 170 or higher, EF will automatically migrate JSON data from NVARCHAR(MAX) data types over to JSON the next time you do a migration, as explained in the What’s New in EF Core 10 doc. That makes it especially important for you to understand how the new JSON indexes work, because they may be coming at you quickly the instant you change your compatibility level.

Read on to see Brent’s take.

Leave a Comment

Index Skip Scans in PostgreSQL 18

Hans-Jürgen Schönig demonstrates a new capability in PostgreSQL:

PostgreSQL 18 brings a couple of performance related features to the table which will help applications to run more efficiently, providing a better and more enjoyable user experience. One of those performance features is called “skip scans”. Most of you might ask yourself at this point: Wow, sounds cool, but what is a skip scan? The purpose of this post is to shed some light and explain how this works, what it does and most importantly: How one can benefit from this feature in real life.

Click through for the demo.

Leave a Comment

Working with JSON Indexes in SQL Server 2025

Koen Verbeeck tries out a new index type:

We’re trying the new JSON data type in SQL Server for data stored as JSON in a table. When we query it using functions such as JSON_VALUE, we see a full table scan is performed for each query. Is there a way we can index the JSON to improve performance?

The JSON index has a somewhat different definition of its structure and there are some limitations to how it works, but for specific JSON-related queries, you can see the improvement.

3 Comments

Common ORM Tuning Tips

Amy Abel shares some advice:

Recently, I thought a database query in a plan was straightforward. It looked innocent until I noticed strange behavior. The deeper I dug, the more I realized many people might be running into the same issue with ORM queries.

Click through for a toy version of the scenario, as well as two common problems with ORM tuning: blind index acceptance (which, admittedly, is a problem with or without ORMs) and implicit conversion on filters.

Leave a Comment

Tuning Window Functions in SQL Server

I have a new video:

In this video, I show you various techniques you can use to make window functions faster, including proper indexing and usage of batch mode. I also demonstrate the performance difference between RANGE and ROWS.

This wraps up my series on window functions, and although I pack a lot of content into the video, I highly recommend checking out the links for deeper dives into performance.

Comments closed

Extending Index Information across Availability Group Replicas

Aaron Bertrand extends a prior article:

In my previous tip, Managing Unused Indexes in SQL Server Availability Groups – Part 1, I showed how I use dynamic SQL to gather index usage statistics for a given table from all replicas in an availability group. Knowing the usage from all workloads is definitely better than focusing on only the primary or a single secondary. But what if I want to make more informed decisions, incorporating row counts, size, and index columns into this output?

Read on to see how you can incorporate this additional information.

Comments closed

Accounting for Index Usage over Availability Groups

Aaron Bertrand wants a cross-replica accounting system:

As a part of optimizing performance, I evaluate index usage across many instances and databases. I often find that some indexes aren’t used much or, at least on first glance, appear to go unused. Since we use availability groups (AG), different workloads run against replicas in different roles. All writes happen on the primary, obviously. However, some queries only happen on read-only secondaries (either because read-only routing is in use, or because some processes are manually directed at specific secondaries, or both). Unfortunately, index usage is not rolled up anywhere across all replicas. This means that looking at the primary alone gives an incomplete picture. How do I make sure I account for index activity everywhere, not just on the primary?

This is part one of a series but already has enough to get us started.

Comments closed

Bitmap Indexes and Deadlocks in Oracle

David Fitzjarrell looks at bitmap indexes:

Bitmap indexes can be very useful, especially when NULL columns are present, as a bitmap index will include such values when btree indexes may not, such as entirely null index keys. Unfortunately bitmap indexes do not behave well with concurrent transactions, where deadlocks may arise because of the bitmap index.

Oracle will trap, report and “resolve” deadlocks by assessing the situation, determining which session created the deadlock and killing the ‘offending’ session, with no manual intervention required. The trace file generated reports this as an issue with application coding and/or logic and in many cases this is the likely cause. Enter the bitmap index and a concurrent transaction and, mysteriously, a deadlock may appear, confounding the developer and the DBA.

Read on to learn more about how bitmap indexes can provide a (potentially) strange source of deadlocks.

Comments closed

PostgreSQL and (Lack of) Clustered Indexes

Brent Ozar shares a surprise if you’re coming from the SQL Server world:

Postgres starts with a very different assumption: it uses multi-version concurrency control (MVCC, or what SQL Server folks call RCSI) by default, right from the get-go. When we update rows, Postgres automatically makes new versions of the rows, storing them inside the same table. There’s no need to enable it – it’s on for all databases, by default.

So because Postgres is constantly creating new versions of rows, it doesn’t really make sense to store the table itself in some kind of order.

Every table is a heap.

This fundamental storage difference has some ramifications for query tuning and indexing strategy that makes the two platforms quite different.

Comments closed