数据库单表拆分问题

本文探讨了单一数据库内分表的实践,指出其在大多数情况下并非理想选择,并提供了替代方案,如归档、读写分离及水平拆分等。

本期焦点问题:单一数据库内分表

本期多个项目出现了在单一数据库内分表的情况,典型的做法是:

某个表(表A)预期会有几千万乃至上亿条数据,于是在单库内拆分成若干张独立的表: A_1, A_2, A_3, … , A_n用“表名+后缀”来区分。

 

在绝大多数情况下,这并不是合适的做法,下表给出了库内分表对一些关键指标的影响:

项目

库内分表

应用开发难度

比单表高

需要管理数据的路由,跨表查询,排序等都较复杂。

未来拆库难度

比单表高

需要对多个表进行数据迁移,同时应用

表结构变更的难度

比单表高

除了耗时,还要变更多个表。

查询性能

走索引,和单表无明显差别。

全表扫描,如果并发执行,会比单表快一些。

写入性能

和单表比无明显差别

并发性能

对行锁无影响,会减少表锁冲突,但是按主键更新不加表锁。

 

从上表可以看出,库内分表提供的好处非常微小,而且在我们的业务场景下也基本用不到这些好处。但是却带来程序设计、运维等多方面的困难,

基于这些因素,我们不赞成使用库内分表这种设计方式。

 

那当库表出现以下几种情况时,如何来应对?

1.       记录数高

一般我们不建议单表出现1千万行以上的数据。如果业务上出现了这样的数据,首先要考虑的是通过归档来降低数据量。

归档可以有效把冷热温数据分开,同时,温数据还可以设计成在低级别SLA下提供服务。

 

对于不能归档的数据,主要是主数据,如用户,商品。可根据tps/qps及它们之间的比例、应用对数据一致性的要求、磁盘空间的大小来决定是做读写分离或水平拆分。

但主数据一般都是高访问量的共享数据,正常应该通过拆库来保证性能。

 

2.       慢查询

慢查询的出现不能想当然归于表的记录数太多,表的记录数和慢查询之间并没有必然的关系。慢查询出现的常见原因:

l  没有正确使用索引或索引失效,导致全表扫描了

l  表设计不合理,出现了多表Join

l  SQL本身的写法有问题,出现了大量的中间结果

l  SQL返回结果集过大

 

所以慢查询应该重点从表的设计和SQL的写法上去解决,库内分表不是一个好的方案。

 

3.       TPS/QPS

TPS高是拆库的最重要的依据,比如说一些订单表,优惠券表等大表都有数亿条数据,拆分的首要原因就是TPS撑不住了,超过6K从库就会开始有明显延迟。

如果TPS不高但QPS很高,而且对数据的一致性要求不高,可以考虑读写分离方案。

 

 

 

### 数据库拆分的方法和步骤 数据库拆分是一种常见的优化手段,旨在提升数据库性能、可扩展性和维护性。根据拆分方式的不同,拆分主要分为**横向拆分**和**纵向拆分**两种形式。 #### 横向拆分 横向拆分是将一张中的数据按照某种规则划分到多个物理中,这些结构一致,但存储不同的数据子集。这种方式适用于数据量大、访问频率高的场景。例如,可以按照时间、地域或业务模块等维度进行拆分。横向拆分的优点在于可以降低的数据量,从而提升查询效率,同时也便于分布式部署[^3]。 ```sql -- 示例:按年份进行横向拆分 CREATE TABLE orders_2023 AS SELECT * FROM orders WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31'; CREATE TABLE orders_2024 AS SELECT * FROM orders WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31'; ``` #### 纵向拆分 纵向拆分则是将一张中的某些列拆分到不同的中,通常用于将热点数据和非热点数据分离。例如,可以将经常访问的字段作为主,而将较少使用的字段作为扩展。这样可以减少主的体积,提高缓存命中率,从而提升整体性能。这种拆分方式特别适用于字段之间访问频率差异较大的情况[^4]。 ```sql -- 示例:将用户信息拆分为主和扩展 CREATE TABLE user_main ( user_id INT PRIMARY KEY, username VARCHAR(50), email VARCHAR(100) ); CREATE TABLE user_details ( user_id INT PRIMARY KEY, address VARCHAR(255), phone VARCHAR(20), FOREIGN KEY (user_id) REFERENCES user_main(user_id) ); ``` #### 拆分步骤 1. **分析业务需求**:明确拆分的目标,例如是提升性能还是简化维护。根据业务逻辑选择合适的拆分方式。 2. **设计拆分规则**:对于横向拆分,确定拆分的维度,如时间、用户ID等;对于纵向拆分,确定哪些字段属于主,哪些属于扩展。 3. **创建新结构**:根据拆分规则创建新的结构,并确保外键约束和索引设置合理。 4. **迁移数据**:将原有中的数据迁移到新的结构中,确保数据完整性和一致性。 5. **更新应用逻辑**:修改应用程序中的SQL语句,使其能够正确访问拆分后的。 6. **测试与优化**:在生产环境中部署前进行充分的测试,确保拆分后的系统性能达到预期,并根据实际情况进行优化。 #### 数据库范式与拆分 在进行纵向拆分时,可以参考数据库范式理论,尤其是第二范式(2NF)和第三范式(3NF)。通过消除部分依赖和传递依赖,可以将一张拆分多个更规范化的。例如,将学生拆分为学生基本信息和选课信息,以消除冗余数据并提高数据一致性[^2]。 ```sql -- 学生基本信息 CREATE TABLE student_info ( student_id VARCHAR(10) PRIMARY KEY, student_name VARCHAR(50), department_name VARCHAR(50), department_head VARCHAR(50) ); -- 选课信息 CREATE TABLE course_selection ( student_id VARCHAR(10), course_id VARCHAR(10), grade INT, PRIMARY KEY (student_id, course_id), FOREIGN KEY (student_id) REFERENCES student_info(student_id) ); ``` #### 注意事项 - 拆分后需要对查询语句进行调整,可能需要使用JOIN操作来获取完整的数据。 - 拆分策略应尽量简,避免过于复杂的规则,以降低维护成本。 - 在进行拆分前,建议对现有数据进行充分的分析,确保拆分后的结构能够满足未来的扩展需求。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值