Spanner性能优化 #
一、性能优化概述 #
1.1 优化方向 #
text
性能优化方向
├── Schema设计
│ ├── 主键设计
│ ├── 交错表设计
│ └── 索引设计
│
├── 查询优化
│ ├── 使用索引
│ ├── 避免全表扫描
│ └── 优化JOIN
│
├── 事务优化
│ ├── 减少事务大小
│ ├── 使用只读事务
│ └── 批量操作
│
└── 配置优化
├── 节点数量
├── 连接池配置
└── 区域选择
1.2 性能指标 #
text
关键性能指标:
├── 延迟(Latency)
│ ├── P50延迟
│ ├── P99延迟
│ └── 读写延迟
│
├── 吞吐量(Throughput)
│ ├── QPS
│ ├── 写入TPS
│ └── 并发连接数
│
├── 资源使用
│ ├── CPU使用率
│ ├── 存储使用量
│ └── 会话使用率
│
└── 可用性
├── 错误率
├── 重试次数
└── 超时次数
二、Schema设计优化 #
2.1 主键设计 #
sql
-- 不推荐: 单调递增主键产生热点
CREATE TABLE bad_users (
id INT64 NOT NULL, -- 单调递增
name STRING(100)
) PRIMARY KEY (id);
-- 推荐: 使用位反转或分散主键
CREATE TABLE good_users (
id INT64 NOT NULL DEFAULT (GET_NEXT_SEQUENCE_VALUE(SEQUENCE user_seq)),
name STRING(100)
) PRIMARY KEY (id);
-- 推荐: 复合主键分散写入
CREATE TABLE orders (
shard_id INT64 NOT NULL,
order_id INT64 NOT NULL,
user_id INT64
) PRIMARY KEY (shard_id, order_id);
2.2 交错表设计 #
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;
-- 查询时利用交错优势
SELECT u.name, o.order_id, o.amount
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id
WHERE u.user_id = 1;
2.3 索引设计 #
sql
-- 创建合适的索引
CREATE INDEX idx_users_email ON users(email);
-- 复合索引注意顺序
CREATE INDEX idx_orders_user_date ON orders(user_id, order_date);
-- 使用存储索引避免回表
CREATE INDEX idx_users_status_storing ON users(status)
STORING (name, email);
三、查询优化 #
3.1 使用EXPLAIN分析 #
sql
-- 查看执行计划
EXPLAIN SELECT * FROM users WHERE email = 'john@example.com';
-- 查看实际执行统计
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'john@example.com';
3.2 使用索引 #
sql
-- 创建索引
CREATE INDEX idx_users_status ON users(status);
-- 使用索引查询
SELECT * FROM users WHERE status = 'active';
-- 强制使用索引
SELECT * FROM users@{FORCE_INDEX=idx_users_status}
WHERE status = 'active';
3.3 避免全表扫描 #
sql
-- 不推荐: 全表扫描
SELECT * FROM users;
-- 推荐: 使用主键或索引
SELECT * FROM users WHERE user_id = 1;
-- 不推荐: 函数导致索引失效
SELECT * FROM users WHERE UPPER(name) = 'JOHN';
-- 推荐: 避免在条件列上使用函数
SELECT * FROM users WHERE name = 'John';
3.4 优化JOIN #
sql
-- 使用交错表优化JOIN
SELECT u.name, o.order_id
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id
WHERE u.user_id = 1;
-- 使用索引优化JOIN条件
CREATE INDEX idx_orders_user ON orders(user_id);
3.5 分页优化 #
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;
四、事务优化 #
4.1 减少事务大小 #
java
// 不推荐: 大事务
client.readWriteTransaction().run(transaction -> {
// 处理大量数据
for (int i = 0; i < 100000; i++) {
transaction.buffer(Mutation.newInsertBuilder("logs")
.set("log_id").to((long) i)
.build());
}
return null;
});
// 推荐: 批量写入
List<Mutation> mutations = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
mutations.add(Mutation.newInsertBuilder("logs")
.set("log_id").to((long) i)
.build());
}
client.write(mutations);
4.2 使用只读事务 #
java
// 推荐: 只读事务性能更好
try (ReadOnlyTransaction transaction = client.readOnlyTransaction()) {
ResultSet rs = transaction.executeQuery(
Statement.of("SELECT * FROM users"));
// 处理结果
}
4.3 避免热点 #
java
// 不推荐: 热点主键
for (int i = 0; i < 1000; i++) {
mutations.add(Mutation.newInsertBuilder("users")
.set("user_id").to((long) i) // 单调递增
.build());
}
// 推荐: 分散主键
for (int i = 0; i < 1000; i++) {
long id = getNextBitReversedId(); // 位反转
mutations.add(Mutation.newInsertBuilder("users")
.set("user_id").to(id)
.build());
}
五、配置优化 #
5.1 节点数量规划 #
text
节点数量计算:
├── 存储需求: 每1TB数据约需1个节点
├── CPU需求: 每1000 QPS约需1个节点
├── 最终节点数: max(存储需求, CPU需求)
└── 预留20%余量
5.2 连接池配置 #
java
// Java连接池配置
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.SessionPoolOptions;
SessionPoolOptions poolOptions = SessionPoolOptions.newBuilder()
.setMinSessions(10)
.setMaxSessions(100)
.setIncStep(5)
.build();
SpannerOptions options = SpannerOptions.newBuilder()
.setSessionPoolOption(poolOptions)
.build();
5.3 区域选择 #
text
区域选择建议:
├── 单区域用户: 选择最近区域
├── 多区域用户: 选择多区域配置
├── 全球用户: 选择nam-eur-asia1
└── 考虑延迟和成本平衡
六、性能监控 #
6.1 关键指标 #
sql
-- 查看查询统计
SELECT
text,
execution_count,
avg_latency_seconds,
avg_rows
FROM INFORMATION_SCHEMA.QUERY_STATS_TOP_HOUR
ORDER BY avg_latency_seconds DESC
LIMIT 10;
-- 查看表统计
SELECT * FROM INFORMATION_SCHEMA.TABLE_STATS;
-- 查看索引统计
SELECT * FROM INFORMATION_SCHEMA.INDEX_STATS;
6.2 Cloud Monitoring #
bash
# 创建性能告警
gcloud alpha monitoring policies create \
--display-name="Spanner High Latency" \
--condition-display-name="P99 Latency > 100ms" \
--condition-filter='resource.type="spanner_instance" AND metric.type="spanner.googleapis.com/instance/latency"' \
--condition-threshold-value=0.1
6.3 性能分析 #
text
性能分析步骤:
1. 识别慢查询
2. 使用EXPLAIN分析
3. 检查索引使用
4. 优化查询语句
5. 验证优化效果
七、性能最佳实践 #
7.1 Schema设计 #
text
Schema设计建议:
├── 使用位反转主键
├── 使用交错表优化关联
├── 创建合适的索引
├── 使用存储索引
└── 合理设置分区
7.2 查询设计 #
text
查询设计建议:
├── 使用索引查询
├── 避免全表扫描
├── 使用游标分页
├── 使用EXPLAIN分析
└── 优化JOIN操作
7.3 事务设计 #
text
事务设计建议:
├── 减少事务大小
├── 使用只读事务
├── 批量操作
├── 避免热点
└── 处理冲突重试
八、总结 #
性能优化要点:
| 方向 | 关键点 |
|---|---|
| Schema | 主键设计、交错表、索引 |
| 查询 | 使用索引、避免全扫描 |
| 事务 | 减少大小、只读事务 |
| 配置 | 节点数量、连接池 |
最佳实践:
text
1. 优化Schema设计
└── 主键、交错表、索引
2. 优化查询语句
└── 使用索引、避免全扫描
3. 优化事务处理
└── 减少大小、批量操作
4. 监控性能指标
└── 及时发现问题
5. 持续优化改进
└── 定期评估和优化
下一步,让我们学习监控告警!
最后更新:2026-03-27