CockroachDB pipelines writes that declare RETURNING NOTHING
The March beta can run consecutive write statements in parallel. Its initial implementation assumes that writes marked for pipelining are independent.
Waiting for each write to finish before starting the next can serialize work that has no dependency. CockroachDB's March 30 beta introduces parallel execution for consecutive write statements using RETURNING NOTHING. The clause supplies an explicit way for a statement to enter the new pipelined execution path, but the initial implementation places an important obligation on the choice of statements.
The beta release notes describe the user-facing behavior. The implementation change, merged March 28, explains that the session's queue initially uses NoDependenciesAnalyzer. It assumes statements told to run concurrently are independent. The server is not yet inferring that independence from arbitrary SQL.
I accept coordination latency as part of choosing a distributed SQL system with strong consistency goals. Removing unnecessary serial waits is still valuable, provided the application knows which dependencies it is preserving. This change makes that distinction visible in the SQL execution path.
The executor queues selected statement plans
The implementation adds pipelining to sql.Executor. When a statement requests pipelined execution, the executor runs its plan through the session's PipelineQueue. A statement that does not request that execution first waits for all statements already running in the queue.
That produces an explicit synchronization boundary. Consecutive eligible writes can overlap, while the next non-pipelined statement waits for the outstanding work. The implementation description names INSERT, UPSERT, UPDATE, and DELETE as supported statement types for this functionality.
RETURNING NOTHING is therefore more than a cosmetic omission of result rows in this beta. It participates in choosing the execution arrangement. An application should not assume the new parallel behavior applies indiscriminately to every write merely because that write happens not to return interesting data to its caller.
The queue belongs to the session. This is statement-level overlap within that session's executor, not a claim that every individual query plan becomes a distributed parallel plan. Different forms of concurrency can coexist, but they operate at different levels and have different dependencies.
Independence is an input to this first implementation
The initial dependency analyzer assumes independence for statements submitted to run concurrently. That is a concrete limitation. The feature should not be described as a planner that examines arbitrary consecutive writes and proves they can be reordered safely.
A dependency exists when one operation needs the outcome of another. An application that writes data and then computes another write from the first result has a reason to preserve order. Selecting concurrent execution without accounting for that relationship changes the execution assumptions, even if both statements belong to the supported write categories.
Conversely, a group of writes to unrelated data may have no such statement-level dependency. The queue can overlap their work instead of imposing a full completion wait after each plan. The implementation's waiting rule then brings the group to completion before a following non-pipelined operation proceeds.
I find this initial design most useful when explained in terms of those boundaries. The SQL clause identifies the requested behavior, and the implementation states its assumption about the selected statements. That is more informative than a general promise that write-heavy applications become faster.
Overlap does not supply a universal speedup
The release notes give no benchmark number for the pipelined-write change. Its mechanism removes a serial execution requirement for selected consecutive statements, but the benefit depends on what those statements do and which resources they share. Concurrent work can still contend for the same data or execution capacity.
The absence of returned data also removes one obvious reason for the caller to wait between statements. If the caller needs a returned value to construct its next statement, that dependency must be resolved first. The explicit clause fits a narrower case where the application can submit the chosen operations without consuming individual results along the way.
This is an execution improvement with a defined scope. It does not change a dependent workflow into an independent one, and it does not by itself justify changing the logical order an application requires. The initial analyzer makes those limits especially important to the explanation.
The same beta fixes transaction and node-liveness failures
The March release fixes an inconsistency involving one-phase transactions at SNAPSHOT isolation. It also prevents unexpected write intents on node-liveness records that could make the cluster unavailable. These are correctness and availability fixes alongside the new executor capability, not evidence about its speed.
Historical-timestamp reads no longer block writes, and node draining improves to avoid hanging DROP statements after restart. The logging layout also changes, combining the previously separate severity log files into one. Each change affects an existing operational behavior independently of whether an application adopts pipelined writes.
For the new execution path, the defining contract remains the queue and its synchronization point. Selected consecutive writes may run together, while a non-pipelined statement waits for them. In this beta, independence is an assumption supplied by the selection of those writes, with no automatic dependency analysis promised by the implementation.