Spanner最佳实践 #

一、Schema设计最佳实践 #

1.1 主键设计 #

text
主键设计原则:
├── 使用位反转序列
│   └── 避免写入热点
│
├── 复合主键分散写入
│   └── 第一列分散写入
│
├── 避免单调递增
│   └── 会导致热点
│
├── 保持主键简短
│   └── 减少存储和传输
│
└── 考虑查询模式
    └── 支持范围查询
sql
-- 推荐: 使用位反转序列
CREATE TABLE users (
    user_id INT64 NOT NULL 
        DEFAULT (GET_NEXT_SEQUENCE_VALUE(SEQUENCE user_bit_seq)),
    name STRING(100)
) PRIMARY KEY (user_id);

-- 推荐: 复合主键分散写入
CREATE TABLE orders (
    shard_id INT64 NOT NULL,
    order_id INT64 NOT NULL,
    user_id INT64
) PRIMARY KEY (shard_id, order_id);

-- 不推荐: 单调递增主键
CREATE TABLE bad_design (
    id INT64 NOT NULL,  -- 单调递增会产生热点
    name STRING(100)
) PRIMARY KEY (id);

1.2 交错表设计 #

text
交错表使用场景:
├── 父子关系明确
├── 经常一起查询
├── 需要级联删除
├── 层级不超过7层
└── 主键包含父表主键
sql
-- 父表
CREATE TABLE users (
    user_id INT64 NOT NULL,
    name STRING(100)
) PRIMARY KEY (user_id);

-- 子表(交错)
CREATE TABLE orders (
    user_id INT64 NOT NULL,
    order_id INT64 NOT NULL,
    amount FLOAT64
) PRIMARY KEY (user_id, order_id)
INTERLEAVE IN PARENT users ON DELETE CASCADE;

1.3 索引设计 #

text
索引设计原则:
├── 选择高选择性列
├── 复合索引注意顺序
│   ├── 等值条件列在前
│   └── 范围条件列在后
├── 使用存储索引避免回表
├── 避免过多索引
└── 定期评估索引使用
sql
-- 复合索引设计
-- 查询: WHERE status = 'active' AND created_at > ?
CREATE INDEX idx_users_status_created ON users(status, created_at);

-- 存储索引避免回表
CREATE INDEX idx_users_email_storing ON users(email)
STORING (name, created_at);

二、查询优化最佳实践 #

2.1 使用索引 #

sql
-- 创建合适的索引
CREATE INDEX idx_users_email ON users(email);

-- 使用索引查询
SELECT * FROM users WHERE email = 'john@example.com';

-- 强制使用索引
SELECT * FROM users@{FORCE_INDEX=idx_users_email}
WHERE email = 'john@example.com';

2.2 避免全表扫描 #

sql
-- 不推荐: 全表扫描
SELECT * FROM users;

-- 推荐: 使用主键或索引
SELECT * FROM users WHERE user_id = 1;

-- 不推荐: 函数导致索引失效
SELECT * FROM users WHERE UPPER(name) = 'JOHN';

-- 推荐: 避免在条件列上使用函数
SELECT * FROM users WHERE name = 'John';

2.3 分页优化 #

sql
-- 不推荐: OFFSET分页(大数据量性能差)
SELECT * FROM users ORDER BY user_id LIMIT 10 OFFSET 10000;

-- 推荐: 游标分页
SELECT * FROM users
WHERE user_id > 10000  -- 上一页最后的user_id
ORDER BY user_id
LIMIT 10;

2.4 使用EXPLAIN分析 #

sql
-- 查看执行计划
EXPLAIN SELECT * FROM users WHERE email = 'john@example.com';

-- 查看实际执行统计
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'john@example.com';

三、事务最佳实践 #

3.1 减少事务大小 #

java
// 不推荐: 大事务
client.readWriteTransaction().run(transaction -> {
    // 处理大量数据
    for (int i = 0; i < 100000; i++) {
        transaction.buffer(...);
    }
    return null;
});

// 推荐: 批量写入
List<Mutation> mutations = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
    mutations.add(...);
}
client.write(mutations);

3.2 使用只读事务 #

java
// 推荐: 只读事务性能更好
try (ReadOnlyTransaction transaction = client.readOnlyTransaction()) {
    ResultSet rs = transaction.executeQuery(...);
    // 处理结果
}

3.3 处理冲突重试 #

java
// 设置重试策略
TransactionOptions options = TransactionOptions.newBuilder()
    .setCommitRetrySettings(
        RetrySettings.newBuilder()
            .setMaxAttempts(5)
            .build())
    .build();

四、成本控制最佳实践 #

4.1 节点规划 #

text
节点规划建议:
├── 根据存储需求计算
│   └── 每1TB数据约需1个节点
│
├── 根据CPU需求计算
│   └── 每1000 QPS约需1个节点
│
├── 预留20%余量
│   └── 应对峰值和增长
│
└── 定期评估调整
    └── 根据实际使用调整

4.2 存储优化 #

text
存储优化建议:
├── 合理设置字符串长度
├── 删除不需要的数据
├── 使用分区过期
├── 监控存储使用
└── 定期清理备份

4.3 网络优化 #

text
网络优化建议:
├── 使用私有IP
├── 选择就近区域
├── 批量操作减少请求
├── 使用过期读
└── 监控网络流量

五、高可用最佳实践 #

5.1 多区域部署 #

text
多区域部署建议:
├── 根据用户分布选择配置
├── 使用多区域配置
├── 配置自动故障转移
├── 测试故障恢复
└── 监控复制延迟

5.2 备份策略 #

text
备份策略建议:
├── 配置自动备份
├── 设置合适的保留时间
├── 定期测试恢复
├── 重要变更前创建备份
└── 跨区域备份复制

5.3 监控告警 #

text
监控告警建议:
├── 监控关键指标
│   ├── CPU使用率
│   ├── 延迟
│   ├── 存储使用量
│   └── 错误率
│
├── 配置合理告警
│   ├── 多级告警
│   └── 多通知渠道
│
└── 定期审查优化

六、安全最佳实践 #

6.1 权限管理 #

text
权限管理建议:
├── 使用最小权限原则
├── 使用服务账号
├── 定期审查权限
├── 及时撤销不需要的权限
└── 安全存储密钥

6.2 数据安全 #

text
数据安全建议:
├── 使用加密连接
├── 使用私有IP
├── 敏感数据加密
├── 审计日志记录
└── 定期安全评估

七、运维最佳实践 #

7.1 变更管理 #

text
变更管理建议:
├── 使用版本控制
├── 测试环境验证
├── 灰度发布
├── 准备回滚方案
└── 记录变更历史

7.2 监控运维 #

text
监控运维建议:
├── 监控关键指标
├── 配置告警通知
├── 定期巡检
├── 建立应急预案
└── 定期演练

7.3 性能优化 #

text
性能优化建议:
├── 定期分析慢查询
├── 优化Schema设计
├── 更新统计信息
├── 评估索引使用
└── 调整节点数量

八、开发最佳实践 #

8.1 代码规范 #

text
代码规范建议:
├── 使用参数化查询
├── 处理所有错误
├── 实现重试逻辑
├── 使用连接池
└── 添加日志记录

8.2 测试规范 #

text
测试规范建议:
├── 单元测试
├── 集成测试
├── 性能测试
├── 压力测试
└── 混沌测试

8.3 部署规范 #

text
部署规范建议:
├── CI/CD流水线
├── 自动化测试
├── 灰度发布
├── 监控告警
└── 回滚机制

九、总结 #

最佳实践要点:

领域 关键点
Schema 主键设计、交错表、索引
查询 使用索引、避免全扫描
事务 减少大小、只读事务
成本 节点规划、存储优化
高可用 多区域、备份、监控
安全 权限管理、数据安全
运维 变更管理、监控优化

核心原则:

text
1. 设计优先
   └── 好的Schema设计是基础

2. 性能优化
   └── 持续监控和优化

3. 成本控制
   └── 合理规划资源

4. 高可用性
   └── 多区域、备份、监控

5. 安全合规
   └── 权限管理和数据安全

6. 持续改进
   └── 定期评估和优化

恭喜你完成了Spanner学习之旅!

最后更新:2026-03-27