分库分表的使用场景
分库分表主要用于解决单库单表数据量过大导致的性能瓶颈问题。当数据库的数据量或访问量达到一定规模时,单库单表的存储和查询性能会显著下降,影响系统整体性能。常见场景包括:
- 数据量过大:单表数据超过千万级别,查询效率明显降低。
- 高并发访问:单库无法承受高并发读写请求,导致响应延迟。
- 业务拆分:不同业务模块需要独立的数据存储,减少相互影响。
分库分表的实现方式
分库分表通常分为垂直拆分和水平拆分两种方式。
垂直拆分
垂直拆分是根据业务模块将表或字段拆分到不同的库或表中。
- 分库:将不同业务模块的表拆分到不同的数据库,例如用户库、订单库。
- 分表:将一张表的字段拆分为多张表,例如将用户表拆分为基础信息表和扩展信息表。
水平拆分
水平拆分是将同一表的数据按照某种规则分散到多个库或表中。
- 分库:将同一表的数据分散到多个数据库,例如按用户ID哈希分库。
- 分表:将同一表的数据分散到多个表,例如按时间范围分表。
分库分表的技术实现
1. 路由策略
路由策略决定数据如何分布到不同的库或表。常见策略包括:
- 哈希路由:对分片键进行哈希计算,根据结果分配数据。
- 范围路由:按分片键的范围分配数据,例如按时间或ID范围。
- 目录路由:维护一个路由表,记录分片键与库表的映射关系。
2. 中间件选择
分库分表通常借助中间件实现,常见中间件包括:
- ShardingSphere:支持多种分片策略,提供透明化操作。
- MyCat:基于Proxy模式,支持MySQL分库分表。
- TDDL:淘宝开源的分库分表中间件,支持动态路由。
3. 事务与跨库查询
分库分表后,跨库事务和查询成为挑战。解决方案包括:
- 分布式事务:使用XA协议或TCC模式保证事务一致性。
- 全局表:将低频修改的表冗余到所有分库,避免跨库查询。
- 数据聚合:在应用层合并多个分库的查询结果。
分库分表的注意事项
- 分片键选择:选择业务频繁查询的字段作为分片键,避免跨分片查询。
- 扩容问题:设计分片规则时需考虑未来扩容的便捷性。
- 数据一致性:确保分布式环境下的数据同步与一致性。
通过合理的设计和工具选择,分库分表可以有效提升系统性能和扩展性。
分库分表查询方法
分库分表后,查询需要根据数据分布策略进行调整,确保能准确找到目标数据。以下是常用的查询方法:
直接路由查询
根据分片键直接定位到具体库表。例如订单ID为分片键,通过哈希或取模计算确定库表位置。这种方法效率最高,但仅适用于已知分片键的场景。
SELECT * FROM order_1 WHERE order_id = 12345;
广播查询
对所有分片执行相同查询,然后合并结果。适用于无分片键或需要全量数据的场景,但性能较差。
// 伪代码示例:并行查询所有分片
List<Result> results = parallelQuery("SELECT * FROM order_${n} WHERE user_id = 100");
拆分查询
将查询条件拆分为多个分片查询。例如根据用户ID范围查询,先确定用户ID对应的分片,再定向查询。
-- 假设用户ID 100-199在分片1
SELECT * FROM order_1 WHERE user_id BETWEEN 100 AND 199;
索引表查询
维护额外索引表记录分片位置。例如通过商品ID查询订单,先查索引表获取订单ID列表,再根据订单ID分片查询。
-- 先查索引
SELECT order_ids FROM index_table WHERE product_id = 888;
-- 再根据order_ids分片查询
中间件查询
使用ShardingSphere、MyCat等中间件自动处理分片路由。只需编写标准SQL,中间件会解析分片规则并执行。
# ShardingSphere配置示例
shardingRule:
tables:
order:
actualDataNodes: ds_${0..1}.order_${0..15}
tableStrategy:
inline:
shardingColumn: order_id
algorithmExpression: order_${order_id % 16}
查询优化建议
- 尽量携带分片键,避免全表扫描
- 对高频查询字段建立分片键或全局索引
- 避免跨分片JOIN,必要时冗余数据或改用多次查询
- 分页查询需在各分片排序后合并,考虑使用连续分片键
分库分表查询的核心是根据业务特点选择合适路由策略,平衡查询效率与开发复杂度。