专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

百亿数据分库分表核心流程详解

  前言
  俗话说:面试造火箭,入职拧螺丝。尽管99。99的业务都不需要用到分库分表,但是分库分表还是频繁出现在大厂的面试中。
  分库分表涉及到的内容非常多,有很多细节,如果在面试中被问到了,既是挑战,也是机会,如果你能回答好的话,会给你的面试加很多分。
  由于业务量的关系,绝大部分同学都很难有实际分库分表的机会,因此很多同学在碰到这个问题时很容易懵逼。
  因此今天跟大家分享一下分库分表的相关知识,本文内容源于实际高并发海量数据业务下的实战和个人的思考总结。
  什么是分库分表
  分表
  分表指的是在数据库数量不变的情况下,对数据库里面的表进行拆分。
  例如我们将SPU表从一张拆成四张。
  分库
  分库指的是在表数量不变的情况下对数据库进行拆分。
  例如我们本来有一个库里面放了两张表,一张是SPU表,一张是SKU表。我们将这两张表拆到两个不同的库里面去。
  分库分表
  也就是数据库的数量,还有表的数量都发生变更。
  例如我们有一个数据库里面本来有一张SPU表。我们将这个SPU表拆成四张表,并且放在两个数据库里面。
  拆分方式
  当前主要的拆分方式有两种:水平拆分和垂直拆分。
  水平拆分就是从左往右横着切,垂直拆分就是从上往下竖着切。当然具体切几刀,这个要看具体的业务需求。
  水平拆分
  水平拆分指的是在整个表数据结构不发生变更的情况下,将一张表的数据拆分成多张表。因为当单张表的数据量越来越大时,这张表的查询跟写入性能也会相应的变得越来越慢。
  因此这个时候我们可以将单张表拆分成多张表,从而让每张表的数据量都变小,从而可以提供更好的读写性能。
  垂直拆分
  垂直拆分指的是将本来放在一张表的字段拆分到多张表中。
  例如在这个例子中,我们将pic这个字段单独拆分出来,然后剩下的三个字段还保留在原表里面。
  这种场景主要是因为在业务的初期,为了业务的快速发展,我们将商品的所有字段都放在一张表里面。但是随着后面的业务的发展,我们发现这个pic字段可能变得越来越大,从而影响到我们商品的基本信息的查询性能。因此这个时候我们可以将这个pic字段单独拆分出去。
  当然这个pic字段拆分出去之后,它应该要存储这个原来这个商品的这个id。
  为什么需要分库分表
  因为单台MySQL服务器的硬件资源是有限的,随着业务的不断发展,请求量和数据量会不断增加,数据库的压力会越来越大,到了某一时刻,数据库的读写性能可能会开始下降,这个时候数据库就成为请求链路中的瓶颈。
  此时可能就需要我们去对数据库进行优化,业务初期我们可能会使用增加索引、优化索引、读写分离、增加从库等手段来进行优化,但是随着数据量的不断增大,这些优化手段的效果会变得越来越小,此时可能就需要使用分库分表来进行优化,对数据进行切分,将单库和单表的数据量控制在合理的范围内,以保证数据库可以提供高效的读写能力。
  何时需要分库分表
  总体来说:当性能出现瓶颈,并且其他优化手段无法很好的解决的时候。
  我们这边必须首先明确分库分表一般是作为最终的解决手段,我们会优先使用其他的方法来进行优化。常见的优化手段有增加索引、优化索引、读写分离、增加数据库的从库等等。当我们使用这些手段都无法解决的时候,就需要来考虑分库分表。
  单表出现瓶颈:单表数据量较大,导致读写性能较慢。
  单库出现瓶颈:CPU压力过大(busy、load过高),导致读写性能较慢。内存不足(缓存池命中率较低、磁盘读写IOPS过高),导致读写性能较慢。磁盘空间不足,导致无法正常写入数据。网络带宽不足,导致读写性能较慢。
  单表超过千万级,就需要进行分库分表?
  这种说法不完全准确。因为有的表它本身的结构比较简单,字段也比较少。这种表可能即使数据量已经超过了亿级,整体的读写性能也是比较高的。而有的表如果整体的结构比较复杂,字段本身也比较大,可能只是百万级,整体的性能已经比较慢了。所以这个还是得结合自己的业务情况来进行分析。这个千万级只能是作为一个参考。
  如何选择分库分表
  只分表:单表数据量较大,单表读写性能出现瓶颈。经过评估单库的容量和性能可以支撑未来几年的增长。
  只分库:数据库(读)写压力较大,数据库出现存储性能瓶颈。
  分库分表:单表数据量较大,单表读写性能出现瓶颈。数据库(读)写压力较大,数据库出现存储性能瓶颈。
  注意点:
  我们在进行选择的时候,必须以未来三到五年的业务发展情况去进行评估。不能只是以当前的数据量和业务量来进行评估。否则可能就会出现频繁的进行分库分表的情况。因为分库分表整体的代价是比较大的。所以我们最好是进行充分的评估,保证最少可以支撑未来三到五年的业务增长。
  小结
  当数据库出现了读写性能瓶颈的时候,我们优先使用一些比较常规的优化手段来进行解决。例如比较常见的有:增加索引、优化索引、读写分离、增加从库等方式。
  如果使用这些常规的手段也无法解决的时候啊,我们才会去考虑用分库分表来进行解决。
  在使用分库分表的时候,必须充分考虑业务未来的整体发展。至少做到这次分库分表之后,未来的三到五年内不需要再进行分库分表。
  拆分完整流程概览
  1、评估是否需要拆分。主要就是评估是否有其他更轻量的优化手段可以解决问题,从而可以避免进行分库分表。
  2、拆分详细技术方案设计。最核心的内容是拆分SOP,也是我们今天后续要详细讲的内容。
  3、技术方案评审优化。分库分表的整体改动比较大,需要让大家一起评估下方案是否有问题,或者是否存在可以优化的地方。
  4、同步相关影响方。拆分可能需要一些下游配合改造,需要提前周知他们。
  5、正式进入拆分。
  接下来我们来看一下拆分的SOP。
  拆分SOP(核心)
  1、目标评估。
  我们首先要评估本次拆分需要拆成几个库和几个表,这个主要取决于我们的拆分目标,例如:读写能力要提升到现在的X倍、负载降低Y、容量要支撑未来的Z年发展等等。
  在大多数情况下,我们可以将单表的行数作为一个重要参考指标,例如将单表控制在千万级以下。特殊情况下如果你要拆分的表单行数据很大,例如字段很多或者某字段很大,这种情况你需要结合实际的性能表现去评估一个合理的值。
  一个例子:当前数据20亿,5年后评估为100亿。分几个表?分几个库?
  解答:一个合理的答案,1024个表,16个库。按1024个表算,拆分完单表200万,5年后为1000万。
  2、切分策略
  当前主流的方案有3种:范围切分、中间表映射、hash切分。
  范围切分
  范围切分是指按某个字段的区间来进行切分。例如每个表放1000万数据,id从01000万的放在第一个表,1000万2000万放在第2个表,依次类推。
  优点:后续扩容很方便,无需进行迁移数据,甚至可以将后续的表扩容、数据库扩库全部做到自动化。
  缺点:存在明显的写偏移,写流量其实是全部集中在最新的表上。因此范围切分并没有起到将写流量均匀分摊到各个库各个表的效果,同时读流量可能也会存在偏移,因为一般来说,最近增加的数据被查询的概率通常会更大一点。
  中间表映射
  中间表映射是将分表键和数据库的映射关系记录在一个单独的表中,每次路由前先查询该表,得到具体路由的数据库,然后进行操作。
  优点:很灵活,可以随意设置路由规则。
  缺点:引入了额外的单点,增加了复杂度,这个映射表可能也会很大,并且其查询QPS会非常高,怎么保障高性能和高可用会是一个新的问题。
  Hash切分
  通过对分表键进行一定的运算(通常是取模),从而决定路由到哪个库哪个表。
  优点:数据分片比较均匀,读写也会比较均匀的分摊到各个库和各个表。
  缺点:可能存在跨节点查询和分页等问题。
  小结
  目前大多数互联网服务主要使用的是hash切分。
  范围切分存在写流量集中在单表的问题,这个会有严重的写性能问题,特别是随着业务的发展,写流量的QPS会越来越高,这个会成为一个严重的瓶颈,目前看这个方案可能更适合一些归档类的功能。
  中间表映射的方案则是太复杂了,如果你的映射数据太多的话,甚至有可能这个映射表也需要进行分库分表,那就进入恶性循环了。
  不过,虽然中间表映射虽然有一些问题,但是我觉得可能在一些特殊的场景下可以使用,例如大商家问题。如果有少量商家的数据量特别大,导致出现偏移,一种思路是将这些商家的数据使用单独的表存放,这部分大商家通过中间表映射路由,其他的商家还是走hash路由。当然,这只是一个简单的思考,没有经过严格的验证。
  3、选择分表字段
  在单库单表的时候,全部数据都放在一张表中,因此我们可以随意的进行join操作和分页操作,但是如果进行了分库分表,数据会分到不同的数据库和数据表上,可能导致原本进行分页的数据分到了不同的数据库中,从而导致跨库查询等问题。而分表字段就是决定数据如何划分的关键因素,通过合理的选择分表字段,我们可以将原本需要进行分页的数据划分到同一张表上,从而避免跨库查询的问题。
  例子:以美团外卖的商品数据为例,我们可以思考下主要有哪些查询商品的场景。
  第一个是用户视角,我们在点外卖时需要查询商品,但是我们在点外卖时会首先进入到商家页面,所以这个地方有商家id字段。
  第二个是商家视角,商家在后台管理自己的商品,这个地方也有商家id字段。
  因此在美团外卖商品数据的这个例子中,商家id字段作为分表键就是一个比较合理的选择,因为他覆盖了最高频的几个使用场景。
  一个例子:10个库,1000张表:099、100199、200299、。。。
  分表字段:shopId,值为1234
  数据表编号:shopId100012341000234
  数据库编号:shopId10001012341000102
  4、资源准备和代码改造
  新集群的所需数据库资源可以尽早跟DBA申请,特别是拆分集群比较多的情况,一方面是因为DBA搭建新集群需要花一定的时间,另一方面是避免出现资源不足导致延期的情况。
  至于代码的改造,主要会涉及到几个部分:将新集群的数据源引入到我们的服务中支持灵活的灰度读写操作第三是数据全量迁移、一致性校验等任务
  因为整个分库分表过程是不停机,并且无损的拆分,因此拆分过程中新老数据源会同时存在一段时间,在这段灰度期间,我们会通过配置中心和相关规则去灵活的控制究竟是写新库、写老库,还是双写,读操作也类似。
  5、增量数据同步(双写)
  双写是为了保证增量数据在新库和老库都存在。
  写新库是因为我们后续准备切换到新库,因此新库必须要有全部的数据。
  写老库是因为我们不确定拆分过程中是否存在问题,通过写老保证了老库有全部的数据,这样万一新流程有问题的时候,我们可以即使切回老库的流程。从而保障了服务的可用性和稳定性。
  常见方案:同步双写,在所有写数据库的地方进行修改,修改成写两份数据。当然,这个地方一般不会去修改全部的写逻辑,而是在底层使用AOP来实现。异步双写:写老库,监听binlog异步同步到新库中间件同步工具:通过一定的规则将数据同步到目标库表
  异步双写和中间件工具同步两者本质上类似,都是通过binlog的方式将数据写入到新库。只不过一个是你自己做,一个是中间件团队帮你做。
  这几种方式一般来说不会差别太大,同步双写的写入延迟可能会稍微小一点。
  6、全量数据迁移
  光有增量数据同步还没法保证新库有全部的数据,我们还需要将以前的老数据全部迁移到新库中。通过增量同步全量迁移,我们才能保证新库有完整的数据。
  常见方案:自己开发一个任务将老库数据迁移到新库。使用中间件同步工具,将老库数据同步到新库。如果中间件有现成工具支持的话,一般建议好接使用现成的工具,这样自己就不用再花时间去额外开发了。
  注意点:控制好同步速率增量同步和全量迁移会同时进行,因此可能会存在并发写同一条数据,从而可能导致一些数据不一致的问题。
  7、数据校验、优化和补偿
  在全量数据迁移完毕,增量同步也正常运行后,并不能直接将流量切到新库。因为可能存在很多情况,导致新库和老库的数据可能没法完全一致。
  例如:我们的改造存在遗漏的地方,或者说并发修改导致数据问题,等等。因此,我们需要进行新老库的数据校验和补偿,直到新老库的数据一致了,才能进行流量切换。
  方案:增量数据校验全量数据校验人工抽检
  核心流程:读取老库数据读取新库数据比较新老库数据,一致则继续比较下一条数据不一致则进行补偿:新库存在,老库不存在:新库删除数据新库不存在,老库存在:新库插入数据新库存在、老库存在:比较所有字段,不一致则将新库更新为老库数据
  注意点:
  数据校验是整个流程中最重要,通常也是花时间最多的一步。一方面是在并发下会出现很多种不一致的场景,另外是因为这一步是切读之前的最后一个保障,因此我们必须再三确认数据是正确的。否则,切读后可能就会导致一些线上问题。
  8、灰度切读
  在数据一致性校验通过后,我们开始将部分读流量切换到新数据库。
  这一步必须遵循以下几个原则:必须支持灵活的切换,有问题可以及时切回老库。支持灵活的灰度规则,灰度早期我们会先拿少量门店进行灰度,观察一段时间,如果没问题再继续增加灰度门店。依此类推,然后到后面开始逐步使用比例来进行灰度,直到最终我们将全部流量都切到新的数据库上。灰度放量先慢后快,每次放量观察一段时间
  9、binlog切新库
  在读流量全部切换到新库后,此时新流程已经验证通过,我们开始为停写老库做准备,首先就是将监听的binlog从老库切换到新库。
  核心流程:启动新库的binlog,此时下游会同时收到新老库的binlog观察一段时间是否正常如果不正在,则将新库的binlog关闭,排查修复问题如果一切正常,则将老库的binlog关闭,此时监听的binlog切换到新库
  注意点:
  监听binlog的流程我们一般会收敛在团队内部,如果外部团队想监听binlog,一般会使用我们封装过的消息,这样在改造时,对外部团队就基本没有影响,我们改造起来也比较方便。
  10、下游切换数据源
  目前来看,除了binlog之外,主要的下游是数仓。数仓会将商品数据定期同步到hive上,用于进行数据的相关工作,因此需要让数仓同学将数据源切换到新数据源。
  数仓一般是定期同步数据,例如一天同步一次全量数据,对实时性要求不高,因此只需在指定时间内切换即可。
  11、停写老库
  在我们确认老库数据源的所有依赖都切换和下线后,停写老库,此时读写流程全部切换到新数据源。至此,整个拆分流程基本结束。
  完整SOP
  最后我们通过一张流程图来回顾下整个拆分流程,整个流程主要包含5个阶段。
  第一阶段:拆分前的相关准备,包含了拆分的目标评估、切分策略和分表字段的选择,还有数据库相关资源的准备。
  第二阶段:代码改造,主要是将新数据源引入到服务中,同时支持灵活的灰度读写。
  第三阶段:数据迁移,包含了全量和增量数据迁移,还有数据一致性的校验和修复。
  第四阶段:流量迁移,主要是将数据库的读写流量按灰度规则逐步切换到新库。
  第五阶段:停写老库,当读写流量全部迁移到新库,老库的相关依赖都全部下线后,停写老库并释放相关资源。
  相关工具
  1、binlog监听工具DatabusCanal
  关于binlog
  binlog是一个二进制文件,用于记录数据库表结构和表记录的变更。简单点说,就是通过binlog文件你可以知道数据库中究竟哪些数据发生了变更,从什么变成了什么。
  而binlog监听工具主要就是用于监听MySQL产生的binlog,然后进行解析,解析成我们比较容易懂的格式,最后通过一定的手段发送到下游,例如比较常见的方式是消息队列。
  在分库分表中就可以通过binlog监听工具来将老库的数据变更实时同步到新库中,以保证新老库的数据一致。
  2、分库分表工具
  目前主要有两种,一种是增强版JDBC驱动,另一种是数据库代理。
  1)增强版JDBC驱动
  以客户端jar包形式提供了对JDBC的封装,客户端直连数据库
  开源:ShardingJDBC、TDDL、Zebra
  2)数据库代理
  需要单独部署,客户端连接代理服务,代理服务负责跟数据库打交道。
  开源:ShardingProxy、MyCat
  两种方案的核心思想都是类似的,就是他们负责将分库分表的逻辑进行抽象封装,做到让分库分表对使用方无感知,使用方只需按照制定的规则进行简单的配置和开发,就可以像没有分库分表一样正常的使用分库分表规则了。
  两者的主要区别在于使用增强版JDBC驱动只需要依赖一个jar包,此时应用服务还是直连数据库的。
  而数据库代理则需要额外部署一个单独的代理服务,应用服务从之前的直连数据库,变成调用代理服务,由代理服务来负责跟数据库打交道。
  目前使用的比较广泛的是增强版JDBC驱动,一方面是增强版JDBC驱动比较轻量,另外是性能也会比较好。
  分库分表问题
  在我们使用分库分表之后,系统的性能和容量都会有很大的提升,但是也会随之带来一些问题。我们一起来看一下有哪些问题,当前的主流方案是如何解决的。
  1、分布式唯一ID
  在单库单表情况下,我们使用表的自增ID就可以保证ID的唯一性,但是分库分表后,一张表被拆成了多张表,此时自增ID就没办法保证唯一性了。因此,需要引入一种方案来保证ID的唯一性。
  目前主流的方案有3种:UUID、雪花算法、号段模式。
  UUID
  UUID相信大家都不陌生,UUID是JDK中自带的一个工具类。什么都不需要引入就可以直接使用了,同时因为是本地生成的,性能也非常好。
  但是UUID并不适合拿来做MySQl数据库的主键,MySQL的主键一般推荐使用单调递增的数字,这个因为MySQL主键使用的是聚簇索引,会把相邻主键的数据放在相邻的物理存储位置上。
  当MySQL的主键是单调递增时,每次只需要简单的将数据追加到索引的最后面即可,类似于顺序写磁盘。而如果MySQL的主键是无序的,则可能需要将数据插入到之前已有的数据中间。如果这个插入位置所在的数据页不在内存中,则需要先从磁盘读取到内存中,这会导致产生磁盘的随机IO。同时,如果该数据页的空间不足,则可能会产生页分裂,导致需要移动大量数据。
  最后就是,MySQL的普通索引需要存储主键索引值,如果主键值更占用空间了,会导致普通索引的B树层高变高,磁盘IO次数变多,最终导致性能变慢。
  雪花算法
  雪花算法的核心思想是通过一定的规则生成一个64位的long类型数字。除了最高位的1位不用之外,其他63位由三部分组成。分别是41位用于存储时间戳,10位用于存储机器ID,12位用于存储序列号。
  简单来说就是支持部署1024台服务器,同时每台服务器1毫秒最多可以生成4096个ID,也就是每秒可以生成四百零九万个,并且可以使用69年。
  这个量级应该基本可以满足任何业务了,当然在实际使用过程中,这三部分的位数可以结合自己的场景去进行修改。
  号段模式
  在讲号段模式之前,我们先介绍下数据库生成的方式。
  数据库生成指的是使用一个额外表的自增ID来作为分布式ID,因为ID都是由同一张表自增生成,所以可以保证全局唯一性。但是这种方案有个严重的问题,每次使用分布式唯一ID都需要来读写这张表。一旦并发量比较大,数据库会有严重的性能问题。
  号段模式就是在此基础上进行了优化,之前是每次获取分布式ID都需要读写数据库,号段模式优化成批量的方式,每次读写数据库时获取一批ID,例如每次获取1000个,将这1000个ID放在本地缓存中,1000个用完之后再来申请下一批,从而大大降低数据库的读写压力。
  小结
  这三种方案中,目前应用的比较广泛的是雪花算法和号段模式,美团开源的分布式ID生成组件Leaf就是提供了这两种方案,如果大家对底层细节感兴趣的话,可以去自己下载源码来看。
  最后需要说一下的是,对于订单ID这种比较特殊的字段来说,一般可能不会直接使用上述的方案,而是会按照一定的规则去生成。同时可能会携带一些业务字段,例如用户ID和商家ID。
  2、分布式事务
  在分库分表之前,全部的表都在同一个库里,我们可以使用本地事务来保障数据的正确性。引入了分库分表之后,数据库表被分到不同的数据库中,此时就没办法使用本地事务了,因此就需要引入分布式事务来保障数据的正确性,我们来看一下当前有哪些常见的分布式事务。
  2PC
  两阶段提交,核心思想是将事务操作分为两个阶段。
  第一阶段:协调者首先询问所有的事务参与者是否可以执行事务提交操作。
  第二阶段:协调者根据所有参与者的返回结果决定是否提交事务,如果全部的参与者都返回成功,则协调者向所有参与者发送事务提交请求。否则,协调者向所有参与者发送事务中断回滚请求。
  两阶段提交是目前比较出名也是用的相对比较多的分布式事务,优点是整体流程比较简单,缺点是存在同步阻塞、协调者单点等问题。
  TCC
  核心思想是针对每个操作都有一个对应的确认和取消操作。
  TCC中有主服务和从服务两个角色,例如在下单的流程中,首先会走到交易服务,然后交易服务分别请求定订单服务和库存服务进行订单创建和库存扣减,此时交易服务就是主服务,而订单服务和库存服务为从服务。
  TCC的核心流程如下:
  首先,主服务调用所有从服务的try接口,进行业务检查和资源预留。
  接着,主服务根据所有从服务的返回结果决定是否提交事务,如果所有从服务都返回成功,则调用所有从服务的confirm接口执行事务确认提交操作。否则,调用所有从服务的cancel接口执行事务取消,并释放预留资源。
  估计大家应该发现了,TCC其实跟两阶段提交非常像。其实很多分布式事务的思想都是很类似的,核心都是先询问,然后提交。这两者的主要区别在于TCC是应用层的处理,而两阶段提交是数据库层面的处理。
  这两种分布式事务应该是目前分布式事务中比较出名的了,其他的分布式事务还有三阶段提交、本地消息表、事务消息等等,这边不做过多的介绍,有兴趣的可以自己查阅资料。
  高并发业务实际使用
  首先说一下结论:在实际的高并发业务中一般都不会使用强一致性的分布式事务,金融场景是个特例,因为涉及到太多钱了,所以可能会用强一致性的分布式事务。
  更多的是通过各种各样的手段来保证最终的一致性,常见的手段有:回滚、重试、监控、告警、幂等、对账等等,终极手段就是人工补偿。
  我之前在某篇文章中说过:每个看着光鲜亮丽的系统背后可能都有一堆苦逼的程序员在默默的修数据,这个不是开玩笑的。
  例子:
  以外卖下单为例,整个用户下单流程会涉及到很多步骤,最核心的包括:创建订单、扣减商品库存、核销优惠券、核销会员红包等等,如果其中有一步失败,则会导致整个下单流程失败,需要将其他的流程都进行回滚,以保证不会产生资损,否则有可能出现用户下单失败,但是会员红包却被扣掉等情况。
  为了避免网络抖动等情况导致回滚失败,一般都会有回滚重试流程,但是重试一般会有次数上限,因为如果重试多次还是失败,则可能是其他问题,例如代码BUG,这种情况再怎么重试也没用。因此在重试达到上限后,如果还是回滚失败,则需要发送告警,人为介入排查,然后人工修复这些数据。
  而对于这些订单的下游服务来说,例如库存、优惠券等等,就需要做好接口的幂等,如果没做好幂等,可能会导致数据出现重复回滚,造成数据错误和资损。
  当然,从广义上来说,保证最终一致性,也是属于分布式事务的一种。
  为什么不直接使用强一致性事务?
  个人觉得主要有以下几个原因:会带来严重的性能损耗,导致下单流程的耗时增加,最终导致服务吞吐量下降、用户下单体验变差。会引入额外的复杂度,开发和维护成本较高。实际业务中,由于部分成功导致数据不一致的场景,发生的概率比较低。
  总结来说就是一个取舍的问题,目前大部分业务场景,使用强一致性分布式事务的ROI不够高,因此一般不会选择强一致性事务,而是选择柔性事务,保障事务的最终一致性。
  3、跨库JOIN分页查询问题
  在单库单表的时候,全部数据都放在一张表中,因此我们可以随意的进行join和分页操作,但是如果进行了分库分表,数据会分到不同的数据库和数据表上,可能导致原本进行分页的数据分到了不同的数据库中,从而导致跨库查询问题。
  目前业界主流解决方案有以下几种。
  1)选择合适的分表字段
  这个在上文已经详细解释过了。总结来说就是,分表字段的选择,要能保证绝大部分高频查询场景,不会出现跨库的问题。在实际业务中,分表字段选择合理的话,基本可以避免95,甚至99以上的跨库查询问题,从而将问题的难度大大降低了。
  2)使用搜索引擎支持,例如ES
  我们可以将全量数据冗余一份到ES中,当出现分表字段支持不了的跨库查询时,可以使用ES来支持。除此之外,ES也会用于支持一些复杂搜索查询请求。
  使用ES需要注意的是:ES只存储需要进行搜索的字段,查询完ES后再根据关键字段去数据库查询完整的数据,这样是为了控制ES的大小,否则ES会容易过大,导致性能和存储问题。ES只用于支持数据库难以支持的查询,就如上面说的跨库查询、复杂搜索查询,这种复杂的查询一般不会太多,因此可以保障ES的整体压力不会太大。
  3)分开查询,内存中聚合
  这个方案跟使用join其实大同小异。区别在于,join是数据库来做这个聚合操作,分开查询是应用层面来做聚合操作。
  即使不分库分表,当表的数据量比较大时,通常也是建议不要在数据库中使用join操作,而是分开查询,然后在应用层内存中聚合。
  这是因为数据库资源相对应用服务器来说会更宝贵,通常也更容易成为链路中的瓶颈,因此尽量不要让其做复杂的查询,避免占用过多的数据库资源。
  注意点:查询出来的数据量占用内存情况
  4)冗余字段
  如果每次join操作只是为了获取少量的字段,那么可以考虑直接将这些字段冗余到表上。
  小结
  这几种方案在实际工作中都挺常使用的,一般看具体的业务场景选择合适的方案即可。原文出自公众号:程序员囧辉
  原文链接:https:mp。weixin。qq。comsX7ciEPZWLzggfnsCsr6wg

你所不知道的太阳系的基本天文知识,让我们一起来探索一下太阳系包含八颗行星太阳系非常巨大。地球到太阳的距离大约有1亿5000万公里,但这也只是整个太阳系的一小部分。太阳系包括所有受到太阳重力(万有引力)影响的天体。太阳系由太阳本身和围绕你知道为什么现代通信要利用卫星吗?微波通信通过建立中继站实现远距离通信。但这种方式有很大缺点,因为地球上有些地方无法建立中继站。比如,从北京到纽约,中间隔着太平洋,距离有上万千米,如果每隔四五十千米建立一个中继站的考古学家在印度发现神秘巨大石罐考古学家发现很多巨大的石头罐子。(Shutterstock)考古学家在印度新发现65个巨大的石头罐子,有的半露出地面,有的完全埋在地下。据维思(vice)网报导,科学家在印度阿萨姆5年老米粉,总结小米手机4个实用APP,让苹果用户看得都眼馋我是5年老米粉了,一直都很喜欢小米手机,以前是因为小米手机性价比高,现在是因为小米手机好用。作为资深米粉,下面就给大家总结一下小米手机四款实用且有趣的APP吧,我敢保证你绝对不可能苹果员工集体更换安卓手机?因为害怕iPhone遭到监控?就在大家都在购买苹果手机的时候,苹果的员工竟然开始研究换安卓手机了?据悉,美国苹果零售店员工表示,正在策划全员更换Android手机互相联系,原因就是害怕使用iPhone遭到监控。华为FreeBudsPro,主动降噪蓝牙耳机,支持无线充电,下沉300价位说到耳机,就不得不说一下近年来蓝牙耳机的发展,传统的单耳蓝牙耳机已经被新一代的TWS耳机所取代,而随着音质的发展,以及蓝牙5。0以上版本的发布,有线耳机也不再具有高清音质的优势,就一文帮你看懂峰米R1家用激光投影仪前言常言道便宜没好货,古人诚不欺我(狗头。jpg)。之前我为了省钱,不想花银子买更为先进的激光投影仪,入手过几款廉价的普通投影仪,经过一段时间的深度使用,观影体验不是很爽,距离电影充电两小时,游戏50H,78g三模迪摩FPW游戏鼠前言早就不缺充电五分钟,通话两小时的手机,但我早已经找不到能聊两个小时的朋友了。信息化高效化的时代,我们的生活离不开各种和充电相关的产品,然而外设却一直能以真正实现无线,尤其是电竞从2199元跌至1899元,6。8英寸1亿,骁龙888Plus手机同价位无敌手消费者购买手机的要求,主要还是要价格便宜,同时性能也要满足日常使用的需求,当然如果手机的售价便宜的同时性能配置参数更高的话,那么就更加物超所值了。所以在售的这些手机当中,如果销量特iOS16两个功能将带来重大升级,推出时间确定,这些机型不能升级有iPhone手机用户表示自己之所以喜欢iPhone是因为iOS系统,苹果的iOS系统以流畅安全著称,在升级更新方面对iPhone老机型也是比较的照顾,也正是因为iOS系统升级更新iPhone14Pro渲染图曝光确定有金色颜色更深据此前多方爆料,苹果将继续在今年9月举行秋季新品发布会,届时全新的iPhone14系列将正式与大家见面。作为全球最受瞩目的移动设备,该机早早便受到了外界的广泛关注,其中外观上的改变
发布两个月跳水830元,A15芯片实体指纹按键,苹果也不保值了?众所周知苹果手机十分好用,在国内的手机市场里面,高端领域是独一档的存在,安卓阵营完全不能和他比,其产品的保值率向来极高,估计也只有特殊因素的华为能胜过它,但苹果也不是没有栽跟头的时胆固醇也分好坏,35条有趣的胆固醇知识收藏很多人尤其是患有三高和心脑血管疾病的人提到胆固醇就心生恐惧之情,唯恐避之不及。那么我们能离开胆固醇吗?胆固醇也分好坏?低密度胆固醇和高密度胆固醇,哪一种是好的胆固醇?当压力增加时,英超最新积分战报曼城1分优势压利物浦领跑,诺维奇提前4轮降级北京时间昨夜今晨,202122赛季英超联赛第35轮鸣锣开战,率先迎来六场较量。曼城40大胜利兹联,福登助攻双响,罗德里破门,阿克热苏斯建功利物浦客场10小胜纽卡斯尔联,凯塔制胜狼队美媒列出了进入202223赛季,勇士队15名球员的薪资状况和去留勇士队准备在2022年季后赛中夺取总冠军。然而,他们本赛季的工资是联盟中最高的,达到178242289美元,看起来他们下个赛季将再次位居NBA球员工资之首。因此,美媒列出了进入20麦迪的天赋有多出色?对比各项天赋顶级球员,才发现麦迪有多棒在NBA里天赋永远是最重要的,因为天赋最终决定了一名球员的高度。乔丹虽然是探花,但也是因为他所处的年代是传统篮球时代,那个时期中锋当家做主,即便如此乔丹还成为了探花,从这里也能够看华为MateXs2正式发布!携多项创新科技直击痛点谈到折叠屏手机,你身边有多少人在用?不用折叠屏手机的原因又在哪呢?通过此前黑猫投诉的折叠屏手机调查数据显示,折叠屏手机有关屏幕问题的就占了一大半,其中投诉量最大的还是屏幕的折痕问题首轮没抢七,近11年第一回!8年前,第一轮差点出现6场抢七大战随着森林狼第四节再一次被翻盘,今年季后赛的首轮较量全部结束,灰熊拿到最后一张晋级分区决赛的门票。而这也宣告着,今年的季后赛是自1011赛季之后,又一次首轮没有抢七大战的季后赛,这不不想再谈多次被逆转纪录76人主教练里弗斯错不完全在我76人队在季后赛首轮对猛龙连拿3胜听牌后,接着连续吞下2场败仗,由于76人队主教练里弗斯曾经多次在季后赛惨遭逆转,也让越来越多人开始讨论猛龙逆转系列赛的可能性。对此,里弗斯日前受访37分34分!这交易果然互利双赢,詹眉功成名就,他也变成实力派俗话说是骡子是马,拉出来遛遛。NBA季后赛这个舞台,很多超新星都在参赛,有的人表现很出色,有的人表现却不佳。今年的季后赛,塔图姆和东契奇的季后赛统治力越来越强,特雷杨和拉塞尔却出现张常宁高调恩爱,6月大婚与世联赛撞车,4年前一幕或再上演?昨日,女排名将张常宁和丈夫吴冠希第二次拍摄了婚纱照,由于2月14日西方情人节那天二人已经拍摄了一次,对于二次拍摄,不少人觉得这样秀恩爱是否太高调了呢。当然作为球迷来说肯定会第一时间詹姆斯第四节11投7中,但为何13年总决赛波什前板传给的是阿伦?2013年的总决赛是荡气回肠的一轮系列赛,那一年热火队能够拿下总冠军,詹姆斯能够成就自己的2连冠,很多人都认为是波什以及雷阿伦拯救了詹姆斯。其中第6场比赛,几乎全世界都认为马刺队能
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网