benchmarking-transaction-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBenchmarking Transaction Patterns
事务模式基准测试
Guides users through benchmarking, explaining, and comparing two formulations of the same transactional business workflow in CockroachDB: explicit multi-statement transactions versus single-statement CTE transactions. Focuses on performance under contention, fair test methodology, and result interpretation.
Complement to design skills: For general transaction design principles, see designing-application-transactions. For SQL syntax and query patterns, see cockroachdb-sql.
本指南引导用户在CockroachDB中对同一事务业务流程的两种实现方式——显式多语句事务与单语句CTE事务——进行基准测试、原理讲解和对比分析,重点关注高竞争场景下的性能表现、公平测试方法以及结果解读。
设计技能补充说明: 如需了解通用事务设计原则,请查看designing-application-transactions。如需了解SQL语法和查询模式,请查看cockroachdb-sql。
When to Use This Skill
适用场景
- Comparing explicit multi-statement transactions versus CTE-based single-statement transactions
- Benchmarking CockroachDB workloads under high concurrency or hot-key contention
- Investigating retry pressure, p95/p99 latency, or throughput differences between transaction formulations
- Deciding whether to rewrite a multi-step application flow into a single SQL statement
- Setting up a fair side-by-side benchmark with proper reset discipline
- Interpreting benchmark results (throughput, retries, tail latency, failures)
- Explaining why SQL Activity still shows waiting even with CTE transactions
- 对比显式多语句事务与基于CTE的单语句事务
- 在高并发或热键竞争场景下对CockroachDB工作负载进行基准测试
- 排查不同事务实现方式之间的重试压力、p95/p99延迟或吞吐量差异
- 决定是否将多步骤应用流程重写为单条SQL语句
- 设置具备合理重置规则的公平对比基准测试
- 解读基准测试结果(吞吐量、重试次数、尾部延迟、失败次数)
- 解释为何使用CTE事务时SQL Activity仍显示等待状态
Prerequisites
前置条件
- CockroachDB test cluster (do not benchmark on production)
- SQL client or JDBC driver for benchmark execution
- Understanding of CockroachDB SERIALIZABLE isolation and retry behavior
- Familiarity with basic concurrency testing concepts
- CockroachDB测试集群(请勿在生产环境进行基准测试)
- 用于执行基准测试的SQL客户端或JDBC driver
- 了解CockroachDB的SERIALIZABLE隔离级别和重试机制
- 熟悉基础并发测试概念
Core Concept
核心概念
When two implementations perform the same business behavior, the transaction formulation itself can be a primary performance lever under contention.
当两种实现方式执行相同业务逻辑时,事务的编写方式本身可能是高竞争场景下的主要性能影响因素。
Explicit Transaction Model
显式事务模型
The application orchestrates the workflow as separate SQL statements inside a transaction: read state, apply logic, write changes, commit.
sql
BEGIN;
SELECT balance FROM accounts WHERE id = $1;
-- Application decides whether transfer is allowed
UPDATE accounts SET balance = balance - $2 WHERE id = $1;
UPDATE accounts SET balance = balance + $2 WHERE id = $3;
INSERT INTO transfers (from_acct, to_acct, amount, created_at)
VALUES ($1, $3, $2, now());
COMMIT;This keeps the transaction open across multiple statements and often includes application-side decision logic between steps.
应用将工作流编排为事务内的多条独立SQL语句:读取状态、执行逻辑、写入变更、提交事务。
sql
BEGIN;
SELECT balance FROM accounts WHERE id = $1;
-- 应用判断转账是否允许
UPDATE accounts SET balance = balance - $2 WHERE id = $1;
UPDATE accounts SET balance = balance + $2 WHERE id = $3;
INSERT INTO transfers (from_acct, to_acct, amount, created_at)
VALUES ($1, $3, $2, now());
COMMIT;这种方式会在多条语句之间保持事务开启状态,且步骤之间通常包含应用端的决策逻辑。
CTE Transaction Model
CTE事务模型
The same read/decision/write logic is expressed as a single SQL statement, so the database evaluates and applies the business operation atomically without intermediate client orchestration.
sql
WITH debit AS (
UPDATE accounts
SET balance = balance - $2
WHERE id = $1
AND balance >= $2
RETURNING id
), credit AS (
UPDATE accounts
SET balance = balance + $2
WHERE id = $3
AND EXISTS (SELECT 1 FROM debit)
RETURNING id
), ins AS (
INSERT INTO transfers (from_acct, to_acct, amount, created_at)
SELECT $1, $3, $2, now()
WHERE EXISTS (SELECT 1 FROM debit)
AND EXISTS (SELECT 1 FROM credit)
RETURNING id
)
SELECT id FROM ins;将相同的读取/决策/写入逻辑整合为单条SQL语句,由数据库原子性地完成业务操作,无需客户端进行中间编排。
sql
WITH debit AS (
UPDATE accounts
SET balance = balance - $2
WHERE id = $1
AND balance >= $2
RETURNING id
), credit AS (
UPDATE accounts
SET balance = balance + $2
WHERE id = $3
AND EXISTS (SELECT 1 FROM debit)
RETURNING id
), ins AS (
INSERT INTO transfers (from_acct, to_acct, amount, created_at)
SELECT $1, $3, $2, now()
WHERE EXISTS (SELECT 1 FROM debit)
AND EXISTS (SELECT 1 FROM credit)
RETURNING id
)
SELECT id FROM ins;Why CTE Tends to Win Under Contention
为何CTE模式在高竞争场景下更具优势
The explicit version keeps the transaction open across multiple statements, increasing the time window for write conflicts, timestamp pushes, and retries. Under high concurrency, each retry repeats the read and write work and continues contending for the same hot data.
The CTE version collapses the same business logic into a single atomic statement, reducing transaction duration and sharply narrowing the contention window.
显式事务会在多条语句之间保持开启状态,增加了写入冲突、时间戳推进和重试的时间窗口。在高并发场景下,每次重试都会重复读取和写入操作,并持续竞争相同的热点数据。
CTE模式将相同业务逻辑整合为单条原子语句,缩短了事务持续时间,大幅缩小了竞争窗口。
Steps
操作步骤
1. Prepare the Benchmark Environment
1. 准备基准测试环境
Set up a dedicated test database and schema. Do not mix benchmark workloads with other traffic.
sql
CREATE DATABASE IF NOT EXISTS bankbench;
USE bankbench;
CREATE TABLE accounts (
id INT PRIMARY KEY,
balance DECIMAL(18,2) NOT NULL DEFAULT 0
);
CREATE TABLE transfers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
from_acct INT NOT NULL,
to_acct INT NOT NULL,
amount DECIMAL(18,2) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);创建专用的测试数据库和 schema。请勿将基准测试工作负载与其他流量混合。
sql
CREATE DATABASE IF NOT EXISTS bankbench;
USE bankbench;
CREATE TABLE accounts (
id INT PRIMARY KEY,
balance DECIMAL(18,2) NOT NULL DEFAULT 0
);
CREATE TABLE transfers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
from_acct INT NOT NULL,
to_acct INT NOT NULL,
amount DECIMAL(18,2) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);2. Seed the Test Data
2. 生成测试数据
Use multi-row UPSERT for efficient seeding. Single-row inserts distort setup cost.
sql
INSERT INTO accounts (id, balance)
SELECT generate_series(1, 10000), 1000.00
ON CONFLICT (id) DO UPDATE SET balance = 1000.00;使用多行UPSERT高效生成数据。单行插入会扭曲初始化成本。
sql
INSERT INTO accounts (id, balance)
SELECT generate_series(1, 10000), 1000.00
ON CONFLICT (id) DO UPDATE SET balance = 1000.00;3. Run the Explicit Transaction Benchmark
3. 运行显式事务基准测试
Execute with realistic concurrency (e.g., 64-128 workers) and a fixed duration or iteration count. Record throughput, retries, p50/p95/p99 latency, max latency, and failures.
使用真实并发数(如64-128个工作线程)执行测试,设置固定时长或迭代次数。记录吞吐量、重试次数、p50/p95/p99延迟、最大延迟和失败次数。
4. Reset Between Runs for Fair Comparison
4. 测试间重置以保证公平对比
For a fair benchmark, reset account balances between explicit and CTE runs so table size, index size, and account state remain comparable.
sql
UPDATE accounts SET balance = 1000.00;为保证基准测试的公平性,在显式事务和CTE事务测试之间重置账户余额,确保表大小、索引大小和账户状态保持一致。
sql
UPDATE accounts SET balance = 1000.00;5. Run the CTE Transaction Benchmark
5. 运行CTE事务基准测试
Execute with the same concurrency, duration, and parameters as the explicit run.
使用与显式事务测试相同的并发数、时长和参数执行测试。
6. Compare Results
6. 对比测试结果
Always compare these metrics side by side:
| Metric | What to Look For |
|---|---|
| Throughput (txn/s) | Higher is better; CTE typically sustains better under contention |
| Total retries | CTE often reduces to near-zero |
| p50 latency | Median transaction time |
| p95 latency | Tail latency under moderate contention |
| p99 latency | Worst-case tail; explicit model often shows spikes |
| Max latency | Outlier behavior |
| Failures | Non-retryable errors |
务必从以下维度进行对比:
| 指标 | 关注要点 |
|---|---|
| 吞吐量(事务/秒) | 数值越高越好;CTE模式在高竞争场景下通常表现更优 |
| 总重试次数 | CTE模式通常可将重试次数降至接近零 |
| p50延迟 | 事务平均耗时 |
| p95延迟 | 中等竞争场景下的尾部延迟 |
| p99延迟 | 最坏情况尾部延迟;显式模式常出现峰值 |
| 最大延迟 | 异常值表现 |
| 失败次数 | 不可重试的错误次数 |
Benchmark Reference Results
基准测试参考结果
In a reported high-contention run comparing the two models:
| Metric | Explicit | CTE | Change |
|---|---|---|---|
| Throughput | 591.1 txn/s | 1,035.1 txn/s | +75.1% |
| Wall time | 216.5s | 123.7s | -42.9% |
| Average latency | 202.2 ms | 111.3 ms | -45.0% |
| Total retries | 2,270,977 | 0 | -100% |
Extended runs preserved the same directional result at higher total volume, with the explicit model continuing to accumulate retries and occasional failures while the CTE model stayed at zero retries and zero failures.
在某高竞争场景的测试中,两种模式的对比结果如下:
| 指标 | 显式事务 | CTE事务 | 变化率 |
|---|---|---|---|
| 吞吐量 | 591.1 事务/秒 | 1,035.1 事务/秒 | +75.1% |
| 耗时 | 216.5秒 | 123.7秒 | -42.9% |
| 平均延迟 | 202.2 毫秒 | 111.3 毫秒 | -45.0% |
| 总重试次数 | 2,270,977 | 0 | -100% |
在更高数据量的扩展测试中,结果趋势保持一致:显式模式持续累积重试次数并偶尔出现失败,而CTE模式始终保持零重试、零失败。
Impact Summary
影响总结
| Dimension | Explicit Multi-Statement | Single-Statement CTE |
|---|---|---|
| Round trips | Multiple client/server interactions | Single request |
| Transaction lifetime | Longer | Shorter |
| Client retry complexity | Higher | Lower |
| Atomic invariant enforcement | Spread across statements/app logic | Contained in SQL |
| Expected throughput | Lower under contention | Higher under contention |
| Client-visible retries | More likely | Often reduced |
| 维度 | 显式多语句事务 | 单语句CTE事务 |
|---|---|---|
| 往返次数 | 多次客户端/服务器交互 | 单次请求 |
| 事务生命周期 | 更长 | 更短 |
| 客户端重试复杂度 | 更高 | 更低 |
| 原子性约束执行 | 分散在多条语句/应用逻辑中 | 完全由SQL实现 |
| 预期吞吐量 | 高竞争场景下更低 | 高竞争场景下更高 |
| 客户端可见重试 | 更易发生 | 通常大幅减少 |
Decision Guidance
决策指导
Prefer the Explicit Pattern When
优先选择显式模式的场景
- The business workflow truly cannot be expressed cleanly in one SQL statement
- Readability or staged business logic matters more than peak throughput
- The contention level is low enough that retry amplification is not the dominant cost
- 业务工作流确实无法用单条SQL语句清晰表达
- 可读性或分步业务逻辑比峰值吞吐量更重要
- 竞争程度较低,重试放大不是主要成本
Prefer the CTE Pattern When
优先选择CTE模式的场景
- The workflow is contention-heavy
- The operation is naturally atomic
- The application currently performs read-decide-write across multiple statements
- The main goal is higher throughput, lower retries, and more stable p95/p99 latency
- 工作流存在高竞争
- 操作天然具备原子性
- 应用当前通过多条语句执行读取-决策-写入操作
- 主要目标是提升吞吐量、减少重试次数并获得更稳定的p95/p99延迟
Fair Benchmark Rules
公平基准测试规则
- Reset between runs for fair comparison so balances, table size, and index size stay consistent
- Treat no-reset runs as a demo, not an apples-to-apples benchmark
- Use when you want one business unit of work at a time for clean comparison
--batch-size=1 - Compare the right metrics — always include throughput, retries, p50, p95, p99, max latency, and failures
- Use multi-row UPSERT for seeding — single-row seeding distorts setup cost
- 测试间重置数据:保证余额、表大小和索引大小一致,确保公平对比
- 无重置测试仅作演示:不能作为严格的同类对比基准
- 使用:如需每次执行一个业务单元以保证对比清晰
--batch-size=1 - 对比正确的指标:务必包含吞吐量、重试次数、p50、p95、p99、最大延迟和失败次数
- 使用多行UPSERT生成数据:单行生成数据会扭曲初始化成本
Common Misconceptions
常见误区
"CTE always wins in every workload" — No. The claim is narrower: when the same business workflow can be expressed as a single atomic statement and the workload is contention-sensitive, collapsing the transaction shape can materially improve performance and stability.
"SQL Activity showing waiting means CTE failed" — Single-statement CTE execution does not eliminate contention. Statements can still wait on row conflicts, write intents, latches, or scheduling. The right comparison is overall throughput, tail latency, and retry profile.
"Single-statement means no contention" — A CTE can still wait under contention. The benefit is a narrower contention window, not the elimination of contention.
"CTE模式在所有工作负载中都更优"——错误。正确结论是:当相同业务工作流可表达为单条原子语句且工作负载对竞争敏感时,优化事务结构可显著提升性能和稳定性。
"SQL Activity显示等待意味着CTE模式失效"——单语句CTE执行并不能消除竞争。语句仍可能因行冲突、写入意向、锁或调度等待。正确的对比维度是整体吞吐量、尾部延迟和重试情况。
"单语句意味着无竞争"——CTE模式在高竞争场景下仍可能出现等待。其优势在于缩小了竞争窗口,而非消除竞争。
Safety Considerations
注意事项
- Run benchmarks on dedicated test clusters, not production
- Reset data between runs for fair comparison
- Monitor cluster health during benchmark execution
- Use realistic but not destructive concurrency levels
- Validate that benchmark results transfer to your specific workload before making production changes
- 在专用测试集群运行基准测试,请勿在生产环境执行
- 测试间重置数据以保证公平对比
- 基准测试执行期间监控集群健康状态
- 使用真实但无破坏性的并发级别
- 在生产环境做出变更前,验证基准测试结果是否适用于您的特定工作负载
References
参考资料
- CockroachDB Transactions Documentation
- Advanced Client-Side Transaction Retries
- Performance Best Practices
- Comparing Multi-Statement vs Single-Statement Transactions
- Set-Based Operations with CockroachDB
- Deep Dive into Transaction Retry Failures
- Troubleshooting CockroachDB Performance
- CockroachDB Transaction Demo
- CockroachDB Best Practices & Anti-Patterns Demo -- Demos 1-2 show retry patterns and contention scaling under concurrency
- CockroachDB Transactions Documentation
- Advanced Client-Side Transaction Retries
- Performance Best Practices
- Comparing Multi-Statement vs Single-Statement Transactions
- Set-Based Operations with CockroachDB
- Deep Dive into Transaction Retry Failures
- Troubleshooting CockroachDB Performance
- CockroachDB Transaction Demo
- CockroachDB Best Practices & Anti-Patterns Demo -- 演示1-2展示了重试模式和并发下的竞争扩展情况