mysql表中有近千万条数据, CRUD 很慢,如何优化?如何创建分库、分表?问题是什么?你知道中间件的原理吗?
数据量有千万级,占用的存储空间也比较大。可以想象,它不会存储在连续的物理空间中,而是存储在碎片化的链式物理空间中。可能是为了比较长字符串,需要更多的时间去查找和比较,这就导致了更多的时间。
- 可以拆分表,减少单表列数,优化表结构。
- 在确保主键正确的同时,检查主键索引列的顺序,使查询语句中条件列的顺序与主键索引列的顺序一致。
分割主要有两种类型:垂直分割和水平分割。
垂直分表
也称为“将大表拆分成小表”,是根据Column列进行的。一般情况下,表中的列较多,而那些不常用的、数据量大、数据长的(如文本类型列)则被划分为“全表”。一般针对数百列的大表,也避免了查询时因数据量大而带来的“跨页”问题。
垂直分支的目的是分离系统中的不同业务,例如用户数据库、产品数据库、订单数据库。拆分后应该放在几台服务器上,而不是一台服务器上。为什么?想象一下,一个购物网站对外提供服务,对用户、产品、订单等都有CRUD。数据库垂直划分后,如果仍然放在数据库服务器上,随着注册用户数的增加,一个数据库的处理能力就会成为瓶颈,磁盘空间、内存、TPS等都来自于一台服务器。会很紧。所以我们需要把它分成几台服务器,这样就可以解决上面的问题,以后就不会面临单机资源问题了。
数据库业务层面的分离类似于服务的“治理”和“降级”机制。还可以对不同的业务数据分别进行管理、维护、监控、扩展等。数据库往往是应用系统最容易出现的瓶颈,而数据库本身是“有状态的”。相比Web服务器和应用程序,实现“水平扩展”更加困难。数据库连接资源昂贵,单机处理能力有限。在高并发场景下,垂直分库可以在一定程度上突破单机IO、连接数、硬件资源等瓶颈。
水平表分区
对于数据量较大的单个表(如订单表),按照一定的规则(RANGE、HASH模数等)分为多个表。但这些表仍然在同一个数据库中,因此数据库层面的数据库操作仍然存在IO瓶颈。不建议。
水平分库分表
将一张表的数据拆分到多台服务器。每个服务器都有自己的数据库和相应的表,但这些表中的数据集合是不同的。水平分库分表可以有效缓解单机、单库的性能瓶颈和压力,消除IO拥塞、连接数、硬件资源等。
横向分库分表规则
- RANGE一张表为0到10000,一张表为10001到20000;
- HASH 采用商城系统模型。一般情况下,将用户和订单作为主表,然后将其作为附录,以避免跨库事务等问题。获取用户ID,然后取哈希模并将其分发到不同的数据库。
- 地理区域。比如业务可以按照华东、华南、华北来划分。七牛云应该是这样的。
- 按时间分离就是把过去6个月甚至一年前的数据切下来放在另一个表中,随着时间的推移,表中的数据被查询的概率变小,所以不存在需要和“热数据”放在一起,这也是“冷热数据分离”。
分库分表后面临的问题
- 事务支持分库分表后就变成了分布式事务。如果依赖自己数据库的分布式事务管理功能来执行事务,就会付出高性能的代价;如果应用程序有助于控制和形成程序逻辑事务,它也会导致程序负载。
- 跨数据库Join只要做好了切分,跨节点Join问题就不可避免。但良好的设计和分割可以减少这些情况的发生。解决此问题的常见方法是查询实现两次。在第一个查询结果集中找到相关数据ID,并根据该ID发起第二个请求以获取相关数据。产品解决方案分库分表
- 跨节点计数、排序、分组、聚合函数问题这是一类问题,因为一切都要根据整个数据集合来计算。大多数代理不会自动处理合并。解决方案:与解决跨节点Join问题一样,在每个节点获取结果,然后在应用程序端进行Join。与连接不同,每个节点的查询可以并行执行,这使得它们在许多情况下比大型表更快。但如果结果集很大,应用程序的内存消耗就成为问题。
- 数据迁移、容量规划、扩容等问题来自淘宝综合业务平台团队,利用2的倍数模数具有前向兼容的特性(比如对4取余,从1取余)到2)也是1)分配数据,避免了行级数据迁移,但仍然需要表级迁移。同时,扩容的大小和子表的数量也有限制。总的来说,这些方案都不是很合适,并且存在一些缺点,这也体现了Sharding扩展的难度。
- ID问题
- 一旦数据库被分割成多个物理节点,我们将无法再依赖数据库自身的主键生成机制。一方面,分区数据库生成的ID不能保证全局唯一;另一方面,在输入数据以路由 SQL 之前,必须为应用程序提供一个 ID。一些常见的主键生成策略
UUID 使用UUID作为主键是最简单的解决方案,但其缺点也非常明显。由于UUID很长,除了占用大量存储空间外,主要问题就是索引。构建索引和基于这些索引的查询时存在性能问题。 Twitter Snowflake的自分布式ID算法在分布式系统中,很多时候需要生成全局UID。 Snowflake Twitter解决了这个需求,实现起来还是简单的,除了配置不同。信息方面,核心代码是毫秒时间41位机器ID 10位序列12位毫秒。
- 跨分片排序与分页一般情况下,分页应该按照指定的列进行排序。当排序列是分片列时,我们可以通过分片规则轻松找到指定的分片。但当排序字段为非分片字段时,情况就变得更加复杂。为了保证最终结果的准确性,我们需要对不同分片节点上的数据进行排序返回,并对不同分片返回的结果集进行汇总并重新排序,最后返回给用户。如下图:
推荐中间件
作者:codeyuyu
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。