批量操作 #

一、BATCH概述 #

1.1 BATCH特点 #

Cassandra的BATCH语句有以下特点:

text
BATCH特点:

✓ 多个操作作为一个逻辑单元
✓ 支持INSERT/UPDATE/DELETE
✓ 支持条件操作(轻量级事务)
✓ 支持设置TTL和时间戳

1.2 基本语法 #

sql
BEGIN [UNLOGGED | COUNTER] BATCH
[USING option [AND option ...]]
statement [; statement ...]
APPLY BATCH;

二、基本BATCH #

2.1 简单批量操作 #

sql
-- 批量插入
BEGIN BATCH
    INSERT INTO users (user_id, name, email)
    VALUES (uuid(), '用户1', 'user1@example.com');
    INSERT INTO users (user_id, name, email)
    VALUES (uuid(), '用户2', 'user2@example.com');
    INSERT INTO users (user_id, name, email)
    VALUES (uuid(), '用户3', 'user3@example.com');
APPLY BATCH;

2.2 混合操作 #

sql
-- 混合INSERT/UPDATE/DELETE
BEGIN BATCH
    INSERT INTO users (user_id, name, email)
    VALUES (uuid(), '新用户', 'new@example.com');
    UPDATE users SET email = 'updated@example.com'
    WHERE user_id = existing_uuid;
    DELETE FROM users WHERE user_id = deleted_uuid;
APPLY BATCH;

2.3 多表操作 #

sql
-- 跨表操作
BEGIN BATCH
    INSERT INTO users (user_id, name, email)
    VALUES (uuid(), '张三', 'zhang@example.com');
    INSERT INTO user_stats (user_id, login_count)
    VALUES (uuid(), 0);
    INSERT INTO audit_log (log_id, action, timestamp)
    VALUES (uuid(), 'user_created', toTimestamp(now()));
APPLY BATCH;

三、BATCH类型 #

3.1 LOGGED BATCH(默认) #

sql
-- 默认类型,记录到批处理日志
BEGIN BATCH
    INSERT INTO orders (order_id, user_id, amount)
    VALUES (uuid(), user_uuid, 100.00);
    UPDATE user_stats SET order_count = order_count + 1
    WHERE user_id = user_uuid;
APPLY BATCH;
text
LOGGED BATCH特点:

原子性
├── 全部成功或全部失败
├── 写入批处理日志
└── 跨分区保证

性能
├── 有额外开销
├── 适合跨分区操作
└── 操作数量有限制

3.2 UNLOGGED BATCH #

sql
-- 不记录日志,性能更高
BEGIN UNLOGGED BATCH
    INSERT INTO logs (log_id, message, timestamp)
    VALUES (uuid(), 'log1', toTimestamp(now()));
    INSERT INTO logs (log_id, message, timestamp)
    VALUES (uuid(), 'log2', toTimestamp(now()));
    INSERT INTO logs (log_id, message, timestamp)
    VALUES (uuid(), 'log3', toTimestamp(now()));
APPLY BATCH;
text
UNLOGGED BATCH特点:

性能
├── 无日志开销
├── 性能更高
└── 适合同一分区

原子性
├── 不保证原子性
├── 可能部分成功
└── 需要应用层处理

3.3 COUNTER BATCH #

sql
-- 计数器批量更新
BEGIN COUNTER BATCH
    UPDATE user_counters 
    SET login_count = login_count + 1
    WHERE user_id = uuid1;
    UPDATE user_counters 
    SET page_views = page_views + 10
    WHERE user_id = uuid1;
APPLY BATCH;

四、BATCH选项 #

4.1 TTL设置 #

sql
-- 设置BATCH的TTL
BEGIN BATCH
    USING TTL 3600
    INSERT INTO sessions (session_id, user_id)
    VALUES (uuid(), user_uuid);
    INSERT INTO user_sessions (user_id, session_id)
    VALUES (user_uuid, uuid());
APPLY BATCH;

4.2 时间戳设置 #

sql
-- 设置时间戳
BEGIN BATCH
    USING TIMESTAMP 1704067200000000
    INSERT INTO users (user_id, name, email)
    VALUES (uuid(), '张三', 'zhang@example.com');
    UPDATE user_stats SET user_count = user_count + 1
    WHERE stat_id = 'global';
APPLY BATCH;

4.3 组合选项 #

sql
-- 组合TTL和时间戳
BEGIN BATCH
    USING TTL 3600 AND TIMESTAMP 1704067200000000
    INSERT INTO cache (key, value, created_at)
    VALUES ('cache_key', 'cache_value', toTimestamp(now()));
APPLY BATCH;

五、条件BATCH #

5.1 轻量级事务 #

sql
-- 条件批量操作
BEGIN BATCH
    UPDATE users 
    SET email = 'new@example.com' 
    WHERE user_id = uuid1
    IF email = 'old@example.com';
    
    INSERT INTO audit_log (log_id, user_id, action, timestamp)
    VALUES (uuid(), uuid1, 'email_change', toTimestamp(now()));
APPLY BATCH;

5.2 条件结果 #

sql
-- 条件BATCH返回结果
BEGIN BATCH
    INSERT INTO users (user_id, email, name)
    VALUES (uuid(), 'unique@example.com', '张三')
    IF NOT EXISTS;
    
    INSERT INTO user_stats (stat_id, user_count)
    VALUES ('global', 1)
    IF NOT EXISTS;
APPLY BATCH;

-- 返回结果
-- [applied] | user_id | email              | name
------------+---------+--------------------+-------
--      True | uuid    | unique@example.com | 张三

六、BATCH最佳实践 #

6.1 同分区操作 #

sql
-- 推荐:同一分区的操作
BEGIN UNLOGGED BATCH
    INSERT INTO orders (user_id, order_id, amount)
    VALUES (user_uuid, uuid(), 100.00);
    INSERT INTO orders (user_id, order_id, amount)
    VALUES (user_uuid, uuid(), 200.00);
    INSERT INTO orders (user_id, order_id, amount)
    VALUES (user_uuid, uuid(), 300.00);
APPLY BATCH;

6.2 操作数量限制 #

text
BATCH操作数量建议:

推荐
├── < 20个操作
├── 同一分区
└── UNLOGGED BATCH

警告
├── > 20个操作
├── 跨分区
└── LOGGED BATCH

限制
├── 最大操作数:65535
├── 批量大小:有限制
└── 超时设置

6.3 适用场景 #

text
BATCH适用场景:

推荐使用
├── 同一分区的多个操作
├── 需要原子性的操作
├── 维护反范式化数据
└── 审计日志记录

不推荐使用
├── 大量数据导入
├── 纯粹为了批量插入
├── 跨分区的大量操作
└── 高频批量操作

七、性能考虑 #

7.1 LOGGED vs UNLOGGED #

text
性能对比:

LOGGED BATCH
├── 原子性保证
├── 写入批处理日志
├── 额外存储开销
├── 性能较低
└── 适合跨分区

UNLOGGED BATCH
├── 无原子性保证
├── 无日志开销
├── 性能更高
└── 适合同一分区

7.2 性能优化 #

text
BATCH性能优化:

1. 使用UNLOGGED BATCH
   └── 同一分区操作

2. 控制操作数量
   └── < 20个操作

3. 避免跨分区
   └── 跨分区使用LOGGED

4. 合理设置超时
   └── 根据操作复杂度

5. 监控性能
   └── 使用tracing分析

八、错误处理 #

8.1 常见错误 #

sql
-- 操作数量超限
-- 错误:Batch too large

-- 超时
-- 错误:Operation timed out

-- 条件不满足
-- 返回 [applied] = False

8.2 重试策略 #

text
重试策略:

LOGGED BATCH
├── 可以安全重试
└── 幂等性保证

UNLOGGED BATCH
├── 需要谨慎重试
└── 可能导致重复

条件BATCH
├── 检查返回结果
└── 根据条件决定

九、监控BATCH #

9.1 查询追踪 #

sql
-- 启用追踪
TRACING ON;

-- 执行BATCH
BEGIN BATCH
    INSERT INTO users (user_id, name) VALUES (uuid(), '张三');
    INSERT INTO users (user_id, name) VALUES (uuid(), '李四');
APPLY BATCH;

-- 查看追踪结果

9.2 监控指标 #

bash
# 查看BATCH相关指标
nodetool cfstats | grep -i batch

# JMX监控
# org.apache.cassandra.metrics.Batch

十、完整示例 #

10.1 订单创建 #

sql
-- 创建订单并更新统计
BEGIN BATCH
    INSERT INTO orders (
        user_id, order_id, order_date, 
        amount, status, created_at
    ) VALUES (
        ?, ?, ?, ?, 'pending', toTimestamp(now())
    );
    
    INSERT INTO order_items (
        order_id, item_id, product_id, 
        quantity, price
    ) VALUES (?, ?, ?, ?, ?);
    
    UPDATE user_stats 
    SET order_count = order_count + 1,
        total_amount = total_amount + ?
    WHERE user_id = ?;
    
    INSERT INTO audit_log (
        log_id, action, entity_type, 
        entity_id, timestamp
    ) VALUES (
        uuid(), 'order_created', 'order', ?, toTimestamp(now())
    );
APPLY BATCH;

10.2 用户注册 #

sql
-- 用户注册(条件插入)
BEGIN BATCH
    INSERT INTO users (
        user_id, email, name, 
        password_hash, created_at
    ) VALUES (
        uuid(), ?, ?, ?, toTimestamp(now())
    ) IF NOT EXISTS;
    
    INSERT INTO user_emails (
        email, user_id
    ) VALUES (?, ?) IF NOT EXISTS;
    
    UPDATE global_stats 
    SET user_count = user_count + 1
    WHERE stat_id = 'global';
APPLY BATCH;

十一、总结 #

批量操作要点:

  1. BATCH类型:LOGGED、UNLOGGED、COUNTER
  2. 原子性:LOGGED BATCH保证原子性
  3. 性能:UNLOGGED性能更高
  4. 同分区:同分区操作性能最优
  5. 操作数量:控制在20个以内
  6. 条件操作:支持轻量级事务

下一步,让我们学习高级查询!

最后更新:2026-03-27