1. ShardingSphere执行引擎概述
ShardingSphere执行引擎是分片数据库中间件的核心组件之一,负责将经过路由和改写后的真实SQL高效地发送到底层数据源执行。与传统的JDBC直接执行方式不同,执行引擎需要解决分片环境下特有的资源控制和执行效率问题。
在分片场景中,一条逻辑SQL可能被拆分为多条真实SQL,这些SQL需要分发到不同的数据节点执行。执行引擎的核心挑战在于如何平衡两个看似矛盾的目标:
- 资源控制:避免单个查询占用过多数据库连接
- 执行效率:充分利用并行执行提升查询性能
2. 分片SQL执行流程解析
2.1 连接模式选择
ShardingSphere提供了两种基础连接模式:
2.1.1 内存限制模式(MEMORY_STRICTLY)
- 特点:为每个分片创建独立连接并行执行
- 优势:最大化并行度,提高执行效率
- 适用场景:OLAP查询、大数据量处理
- 资源消耗:连接数=分片数
2.1.2 连接限制模式(CONNECTION_STRICTLY)
- 特点:复用同一连接串行执行分片SQL
- 优势:严格限制连接数,节省资源
- 适用场景:OLTP操作、高并发短查询
- 资源消耗:连接数=数据源数
2.2 自动化执行引擎
实际生产环境中,ShardingSphere采用了更智能的自动化执行引擎,其核心创新点包括:
动态连接模式选择:
- 根据maxConnectionSizePerQuery参数
- 实时计算最优执行策略
- 混合模式支持(部分分片并行+部分串行)
死锁预防机制:
- 连接获取同步控制
- 避免交叉等待
- 优化OLTP场景连接获取
3. 执行阶段详解
3.1 准备阶段
3.1.1 结果集分组
// 示例分组逻辑 Map<String, List<SQLExecutionUnit>> executionGroups = new HashMap<>(); for (SQLExecutionUnit each : executionUnits) { String dataSourceName = each.getDataSourceName(); if (!executionGroups.containsKey(dataSourceName)) { executionGroups.put(dataSourceName, new ArrayList<>()); } executionGroups.get(dataSourceName).add(each); }3.1.2 执行单元创建
- 根据分组结果创建执行单元
- 计算每个数据源需要的连接数
- 确定各分片的执行模式(并行/串行)
3.2 执行阶段
3.2.1 并行执行控制
ExecutorService executorService = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() * 2); List<Future<QueryResult>> futures = new ArrayList<>(); for (List<SQLExecutionUnit> group : executionGroups.values()) { futures.add(executorService.submit(() -> executeGroup(group))); }3.2.2 执行事件流
- 执行开始事件
- 执行成功/失败事件
- 结果集获取事件
4. 结果归并处理
4.1 流式归并
- 适用场景:大数据量查询
- 特点:无需全量加载结果到内存
- 实现方式:基于游标逐条处理
4.2 内存归并
- 适用场景:小结果集
- 特点:全量加载后处理
- 排序归并示例:
SELECT * FROM t_order ORDER BY order_id DESC分片执行后需要在内存中进行全局排序
5. 性能优化实践
5.1 参数调优建议
| 参数名 | 默认值 | 建议值 | 说明 |
|---|---|---|---|
| maxConnectionSizePerQuery | 1 | 5-10 | 每个查询最大连接数 |
| executor.size | CPU核数 | CPU核数*2 | 执行线程池大小 |
| fetch.size | -1 | 1000 | 结果集获取批次大小 |
5.2 常见问题排查
连接泄漏:
- 检查是否正确关闭ResultSet/Statement
- 监控连接池使用情况
内存溢出:
- 避免大结果集内存归并
- 使用流式归并替代
执行超时:
- 调整executor.timeout参数
- 优化分片策略减少分片数
6. 最佳实践案例
6.1 电商订单查询优化
原始方案:
- 每月订单分片
- 全量查询导致内存归并压力
优化方案:
// 添加create_time条件缩小查询范围 shardingConfig.getShardingRuleConfig().getTableRuleConfigs() .forEach(table -> table.setActualDataNodes("ds_${2020..2023}.order_${1..12}"));6.2 分页查询陷阱
错误写法:
SELECT * FROM t_order LIMIT 1000000, 10正确写法:
SELECT * FROM t_order WHERE id > 1000000 LIMIT 107. 执行引擎演进方向
- 智能连接池预测
- 自适应归并策略
- 分布式执行计划缓存
- 基于机器学习的参数调优
执行引擎的实际表现往往取决于具体业务场景,建议在测试环境进行充分验证后再上线生产。我们团队在使用过程中发现,对于TP类业务,连接限制模式配合适当的分片策略往往能取得最佳效果;而对于AP类查询,则需要根据数据量大小谨慎选择归并方式。