Identifying Fast-Path vs Distributed Transactions with EXPLAIN (ANALYZE, DIST)

YugabyteDB has always supported multiple transaction execution paths under the hood, but determining which path a statement actually used often required inference, deep metrics, or indirect signals.

Starting in YugabyteDB 2024.2.7, that guesswork is gone.

A new enhancement expands EXPLAIN (ANALYZE, DIST) output to explicitly show the transaction type, making it much easier to reason about performance, scalability, and correctness.

✨ What’s New in 2024.2.7

In v2024.2.7.0, YugabyteDB adds a new line to the execution plan:

				
					Transaction: Fast Path
				
			

or implicitly, when absent:

				
					Transaction: Distributed
				
			

This enhancement (GitHub issue #14804) provides a formal, user-visible way to identify whether a statement ran as a fast-path (single-shard) transaction or a distributed transaction.

That single line unlocks a lot of insight.

🧠 Why Knowing the Transaction Path Matters
1️⃣ Performance & Latency

Fast-path transactions are dramatically cheaper than distributed ones:

  • ● They bypass the transaction status tablet

  • ● They skip IntentsDB

  • ● Writes go directly to RegularDB

  • ● Fewer RPCs, fewer round trips, and lower commit latency

In practice, this often means latencies much closer to single-node PostgreSQL, especially for point updates and single-row operations.

Being able to see that a query used the fast path removes ambiguity when evaluating latency improvements or regressions.

2️⃣ Scalability Awareness

YugabyteDB scales write throughput linearly… but only when queries are structured to take advantage of it.

If a query unintentionally falls back to the distributed transaction path, you may see:

  • ● Higher coordination overhead

  • ● Increased write amplification

  • ● Slower scaling as nodes are added

By inspecting EXPLAIN (ANALYZE, DIST), you can now quickly validate whether your workload is aligned with YugabyteDB’s horizontal scaling model.

3️⃣ Observability & Debugging

Transaction path affects what you can observe:

  • ● Fast-path transactions may not appear the same way in pg_locks

  • ● Awaiting lock details may be missing

  • ● Transaction coordinators do not track them like distributed transactions

With this change, you no longer have to infer why certain lock or transaction metadata looks incomplete… you can confirm the execution path directly.

4️⃣ Spotting Optimization Opportunities

This feature is especially useful for catching subtle performance killers, such as:

  • ● Multi-statement BEGIN … COMMIT blocks that could be collapsed into a single statement

  • ● Queries that look single-row but aren’t (e.g., IN (...))

  • ● Type mismatches that force distributed execution

  • ● Missed opportunities to use RETURNING to stay on the fast path

Seeing the transaction type in the plan makes these issues immediately obvious.

🧪 Example: Fast Path vs Not

Let’s look at a simple example using YugabyteDB 2024.2.7.1.

				
					SELECT split_part(version(), '-', 3) yb_version;
CREATE TABLE test(id INT PRIMARY KEY, c1 TEXT DEFAULT 'A');
INSERT INTO test SELECT generate_series(1, 1000);
				
			

Example:

				
					yugabyte=# SELECT split_part(version(), '-', 3) yb_version;
 yb_version
------------
 2024.2.7.1
(1 row)

yugabyte=# CREATE TABLE test(id INT PRIMARY KEY, c1 TEXT DEFAULT 'A');
CREATE TABLE

yugabyte=# INSERT INTO test SELECT generate_series(1, 1000);
INSERT 0 1000
				
			
✅ Single-Row Update (Fast Path)
				
					EXPLAIN (ANALYZE, DIST)
UPDATE test
SET c1 = 'B'
WHERE id = 1;
				
			

Example:

				
					yugabyte=# EXPLAIN (ANALYZE, DIST) UPDATE test SET c1 = 'B' WHERE id = 1;
                                          QUERY PLAN
----------------------------------------------------------------------------------------------
 Update on test  (cost=0.00..4.11 rows=1 width=128) (actual time=1.366..1.366 rows=0 loops=1)
   ->  Result  (cost=0.00..4.11 rows=1 width=128) (actual time=0.002..0.003 rows=1 loops=1)
         Storage Table Write Requests: 1
 Planning Time: 7.550 ms
 Execution Time: 1.413 ms
 Storage Read Requests: 0
 Storage Rows Scanned: 0
 Catalog Read Requests: 13
 Catalog Read Execution Time: 7.010 ms
 Catalog Write Requests: 0
 Storage Write Requests: 1
 Storage Flush Requests: 0
 Storage Execution Time: 7.010 ms
 Transaction: Fast Path
 Peak Memory Usage: 0 kB
(15 rows)
				
			

Note the line:

				
					Transaction: Fast Path
				
			
❌ Multi-Row Update (Not Fast Path)
				
					EXPLAIN (ANALYZE, DIST)
UPDATE test
SET c1 = 'B'
WHERE id IN (1, 2, 3);
				
			

Example:

				
					yugabyte=# EXPLAIN (ANALYZE, DIST) UPDATE test SET c1 = 'B' WHERE id IN (1, 2, 3);
                                                       QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
 Update on test  (cost=0.00..4.11 rows=1 width=128) (actual time=1.915..1.915 rows=0 loops=1)
   ->  Index Scan using test_pkey on test  (cost=0.00..4.11 rows=1 width=128) (actual time=1.873..1.877 rows=3 loops=1)
         Index Cond: (id = ANY ('{1,2,3}'::integer[]))
         Storage Table Read Requests: 1
         Storage Table Read Execution Time: 0.315 ms
         Storage Table Rows Scanned: 3
         Storage Table Write Requests: 3
 Planning Time: 0.101 ms
 Execution Time: 5.163 ms
 Storage Read Requests: 1
 Storage Read Execution Time: 0.315 ms
 Storage Rows Scanned: 3
 Catalog Read Requests: 3
 Catalog Read Execution Time: 2.762 ms
 Catalog Write Requests: 0
 Storage Write Requests: 3
 Storage Flush Requests: 1
 Storage Flush Execution Time: 2.549 ms
 Storage Execution Time: 5.626 ms
 Peak Memory Usage: 59 kB
(20 rows)
				
			

Notice what’s missing:

				
					-- No "Transaction: Fast Path"
				
			

Even though this still uses the primary key, the update affects multiple rows, which requires a distributed transaction.

The plan makes that distinction explicit.

🗺️ How This Fits into YugabyteDB’s Transaction Architecture

Under the hood, YugabyteDB supports multiple transaction execution paths, optimized for different access patterns:

  • ● Fast Path (Single-Row / Single-Shard)

  • ● Distributed Transactions (Multi-Row / Multi-Shard)

This feature doesn’t change how transactions work… it makes them visible.

🎯 Takeaways
  • ● New in 2024.2.7: EXPLAIN (ANALYZE, DIST) now shows the transaction type

  • Fast-path vs distributed execution is no longer guesswork

  • This improves:

    • ○ Performance tuning

    • ○ Debugging

    • ○ Observability

    • ○ Query design validation

  • A small line in the plan delivers big insight

Have Fun!