Table-Level Locks for Concurrent DDL

Starting in YugabyteDB 2025.2, a new table-level locking capability (πŸ“Œ Early Access) significantly improves how YugabyteDB handles concurrent DDL. Instead of failing when multiple schema operations overlap, conflicting DDL is now queued at the table level.

This is a big quality-of-life improvement for operators and developers who routinely run background maintenance (like ANALYZE) while schema changes are happening, as well as for teams using CI/CD pipelines, automated migration tools, or online index builds where overlapping DDL was previously a common source of flaky failures.

🧠 The Problem (Before 2025.2)

Historically, YugabyteDB behaved like this:

  • ● DDL changes bump a table’s schema/catalog version

  • ● Long-running operations (like ANALYZE) see the schema change mid-flight

  • ● The operation fails with a catalog version mismatch

  • ● Users must retry manually or via automation

This was technically correct… but operationally painful.

πŸ§ͺ Example: Concurrent DDL Failure (Feature Disabled / Pre-2025.2)
Session 1: ANALYZE
				
					yugabyte=# SELECT split_part(version(), '-', 3) AS yb_version;
 yb_version
------------
 2024.2.3.1

yugabyte=# ANALYZE big;
WARNING: 'analyze' is a beta feature!
LINE 1: ANALYZE big;
HINT: Set 'ysql_beta_features' yb-tserver gflag to true to suppress the warning for all beta features.
ERROR: schema version mismatch for table 000033cf000030008000000000004000: expected 4, got 3
CONTEXT: Catalog Version Mismatch: A DDL occurred while processing this query. Try again.
				
			
Session 2: Concurrent DDL
				
					yugabyte=# CREATE INDEX uh_oh_idx ON big(c1);
				
			

πŸ“Œ Result:

  • The index build succeeds, but ANALYZE fails and must be rerun.
✨ What’s New in YugabyteDB 2025.2

With table-level locks enabled:

  • ● YugabyteDB takes explicit table locks for DDL

  • ● Conflicting DDL operations wait instead of aborting

  • ● Long-running DDL (like ANALYZE) can complete safely **

  • ● Subsequent DDL proceeds once the lock is released

In other words:

  • ❌ Fail fast due to schema mismatch
    βœ… Queue politely, then proceed
πŸ§ͺ Example: Concurrent DDL with Table-Level Locks Enabled (2025.2 EA)
Enable the Feature
				
					yugabyted start \
  --tserver_flags="allowed_preview_flags_csv=ysql_yb_ddl_transaction_block_enabled,ysql_yb_ddl_transaction_block_enabled=true,enable_object_locking_for_table_locks=true"
				
			
Session 1: Long-Running ANALYZE
				
					yugabyte=# SELECT split_part(version(), '-', 3) AS yb_version;
 yb_version
------------
 2025.2.0.0
(1 row)

yugabyte=# ANALYZE big;

				
			
  • ● ANALYZE starts and acquires a table-level lock

  • ● It continues running

Session 2: Concurrent DDL
				
					yugabyte=# CREATE INDEX uh_oh_idx ON big(c1);
				
			
⏳ Behavior with locks enabled
  • ● CREATE INDEX waits

  • ● No catalog mismatch

  • ● No failure

Completion Order

  • 1. ANALYZE finishes

  • 2. Lock is released

  • 3. CREATE INDEX proceeds

  • 4. Both complete successfully

πŸ“Œ Key difference: no retries, no wasted work.

πŸ“Œ Quick Callout: ANALYZE Is DDL in YugabyteDB

In YugabyteDB, ANALYZE is treated as a DDL-style operation because it updates system catalog metadata used by the query planner. As a result, it historically conflicted with other DDL, such as CREATE INDEX or ALTER TABLE, leading to catalog version mismatch errors when run concurrently.

In YugabyteDB 2025.2, ANALYZE itself is also more efficient, thanks to improved sampling, and automatic analyze is enabled by default, meaning manual ANALYZE is needed far less often. if at all.

When you do run it manually, table-level locks ensure it now waits safely instead of failing if another DDL is in progress.

🚦 Real-World Scenarios This Fixes
  • ● Background maintenance overlapping with schema changes

  • ● CI/CD and automated migration pipelines

  • ● Online index builds on hot tables

  • ● Multi-tool environments issuing concurrent DDL

⚠️ Early Access (EA) Notes
  • ● Status: Early Access in 2025.2

  • ● Disabled by default

  • ● Requires explicit gFlag enablement

  • ● Intended for validation and early adoption

▢️ How to Enable Table-Level Locks
				
					yugabyted start \
  --tserver_flags="allowed_preview_flags_csv=ysql_yb_ddl_transaction_block_enabled,ysql_yb_ddl_transaction_block_enabled=true,enable_object_locking_for_table_locks=true"
				
			
🐘 PostgreSQL Alignment

This feature brings YugabyteDB much closer to PostgreSQL’s DDL behavior. Like Postgres, conflicting DDL now waits instead of failing, providing familiar, predictable semantics, while still operating in a distributed environment.

🧾 Summary
Before After (2025.2 EA)
Concurrent DDL fails Concurrent DDL queues
ANALYZE may abort ANALYZE completes
Manual retries Predictable execution
No table-level locks Explicit table-level locking

Have Fun!

This is Apollo, a Northern White-faced Owl at the National Aviary in Pittsburgh, and yes… he absolutely knows he’s adorable. πŸ¦‰πŸ‘€