桥下の民 - ShardingSphere
type: channel
link: https://www.wordplay.work/index.php/category/ShardingSphere
items: 跨库分页方案
items: ShardingSphere--跨库分页问题
items: 数据分片--使用规范
items: 数据分片--内核剖析
items: 数据分片--核心概念
items: ShardingSphere简介
items: 分库分表概述

跨库分页方案
type: item
date: 2023-06-25T16:22:00+00:00
description: 一、需求 互联网很多业务都有分页拉取数据的需求，例如： 1、微信消息过多时，拉取第N页消息 2、京东下单过多时，拉取第N页订单 3、浏览58同城，查看第N页帖子 这些业务场景对应的消息表，订单表，帖子表分页拉取需求有这样一些特点： 1、有一个业务主键id, 例如msg_id, order_id, tiezi_id 2、分页排序是按照非业务主键id来排序的，业务中经常按照时间time来排序order by 在数据量不大时，可以通过在排序字段time上建立索引，利用SQL提供的offset/limit功能就能满足分页查询需求： select * from t_msg order by time offset 200 limit 100 select * from t_order order by time offset 200 limit 100 select * from t_tiezi order by time offset 200 limit 100 此处假设一页数据为100条，均拉取第3页数据。 二、分库需求 高并发大流量的互联网架构，一般通过服务层来访问数据库，随着数据量的增大，数据库需要进行水平切分，分库后将数据分布到不同的数据库实例（甚至物理机器）上，以达到降低数据量，增加实例数的扩容目的。 一旦涉及分库，逃不开“分库依据”patition key的概念，使用哪一个字段来水平切分数据库呢：大部分的业务场景，会使用业务主键id。 确定了分库依据patition key后，接下来要确定的是分库算法：大部分的业务场景，会使用业务主键id取模的算法来分库，这样即能够保证每个库的数据分布是均匀的，又能够保证每个库的请求分布是均匀的，实在是简单实现负载均衡的好方法，此法在互联网架构中应用颇多。 举一个更具体的例子： 用户库user，水平切分后变为两个库，分库依据patition key是uid，分库算法是uid取模：uid%2余0的数据会落到db0，uid%2余1的数据会落到db1。 仍然是上述用户库的例子，如果业务要查询“最近注册的第3页用户”，该如何实现呢？单库上，可以 select * from t_user order by time offset 200 limit 100 变成两个库后，分库依据是uid，排序依据是time，数据库层失去了time排序的全局视野，数据分布在两个库上，此时该怎么办呢？ 如何满足“跨越多个水平切分数据库，且分库依据与排序依据为不同属性，并需要进行分页”的查询需求，实现 select * from T order by time offset X limit Y的跨库分页SQL，是本文将要讨论的技术问题。 二、全局视野法 如上图所述，服务层通过uid取模将数据分布到两个库上去之后，每个数据库都失去了全局视野，数据按照time局部排序之后，不管哪个分库的第3页数据，都不一定是全局排序的第3页数据。 那到底哪些数据才是全局排序的第3页数据呢，暂且分三种情况讨论。 2.1、极端情况，两个库的数据完全一样 如果两个库的数据完全相同，只需要每个库offset一半，再取半页，就是最终想要的数据（如上图中粉色部分数据）。 2.2、极端情况，结果数据来自一个库 也可能两个库的数据分布及其不均衡，例如db0的所有数据的time都大于db1的所有数据的time，则可能出现：一个库的第3页数据，就是全局排序后的第3页数据（如上图中粉色部分数据）。 2.3、一般情况，每个库数据各包含一部分 正常情况下，全局排序的第3页数据，每个库都会包含一部分（如上图中粉色部分数据）。 于不清楚到底是哪种情况，所以必须每个库都返回3页数据，所得到的6页数据在服务层进行内存排序，得到数据全局视野，再取第3页数据，便能够得到想要的全局分页数据。 再总结一下这个方案的步骤： （1）将order by time offset X limit Y，改写成order by time offset 0 limit X+Y （2）服务层将改写后的SQL语句发往各个分库：即例子中的各取3页数据 （3）假设共分为N个库，服务层将得到N*(X+Y)条数据：即例子中的6页数据 （4）服务层对得到的N*(X+Y)条数据进行内存排序，内存排序后再取偏移量X后的Y条记录，就是全局视野所需的一页数据 方案优点：通过服务层修改SQL语句，扩大数据召回量，能够得到全局视野，业务无损，精准返回所需数据。 方案缺点（显而易见）： （1）每个分库需要返回更多的数据，增大了网络传输量（耗网络）； （2）除了数据库按照time进行排序，服务层还需要进行二次排序，增大了服务层的计算量（耗CPU）； （3）最致命的，这个算法随着页码的增大，性能会急剧下降，这是因为SQL改写后每…

ShardingSphere--跨库分页问题
type: item
date: 2023-06-25T15:57:00+00:00
description: 一、问题 假设页大小20，如从从库im_team_messsage0，im_team_messsage1查询，使用者编写的sql如下（只查询第1000行到第1010行）。 SELECT * FROM im_team_messsage ORDER BY send_at DESC LIMIT 1000, 10; shardingsphere的改写引擎会对此sql进行改写，可以看到ss将limit后解析成从第一行开始查询到第1010行。 SELECT * FROM im_team_messsage0 ORDER BY send_at DESC LIMIT 0, 1010; SELECT * FROM im_team_messsage1 ORDER BY send_at DESC LIMIT 0, 1010; 数据库端的查询压力都是差不多的, 因为都是要差不多要扫描1010行才能取得到数据。不同的是改写sql后, 客户端的内存消耗和网络消耗变大了。 shardingsphere巧妙地利用流式处理和优先级队列结合的方式(“流式归并”)，消除了客户端内存消耗的压力, 但是网络消耗的影响依然是无法消除。 二、如何避免使用limit带来的效率问题 有很多方法可以避免使用LIMIT进行分页。比如构建行记录数量与行偏移量的二级索引，或使用上次分页数据结尾ID作为下次查询条件的分页方式等。 2.1、使用上次分页数据结尾ID作为下次查询条件 前提：使用shardingsphere分布式id递增雪花算法保证id呈现连续性 使用上次分页数据结尾ID作为下次查询条件： 但同时需要注意的是，由于排序的需要，大量的数据仍然需要传输到ShardingSphere的内存空间。 因此，采用LIMIT这种方式分页，并非最佳实践。 由于LIMIT并不能通过索引查询数据，因此如果可以保证ID的连续性，通过ID进行分页是比较好的解决方案，例如： SELECT * FROM im_team_message WHERE id > 100000 AND id <= 100010 ORDER BY id; 或通过记录上次查询结果的最后一条记录的ID进行下一页的查询，例如： SELECT * FROM im_team_message WHERE id > 10000000 LIMIT 10; 同理，使用上次分页数据结尾的时间戳作为下次查询条件也可以（按照时间进行排序）。 2.2、二次查询法 这种方法能够满足业务的精确需要，无需业务折衷，又高性能的方法，缺点是业务代码复杂且需要进行两次数据库查询。 三、分页子查询（Mysql、Oracle） Oracle和SQLServer的分页都需要通过子查询来处理，ShardingSphere支持分页相关的子查询。 Oracle 支持使用rownum进行分页： SELECT * FROM (SELECT row_.*, rownum rownum_ FROM (SELECT o.order_id as order_id FROM t_order o JOIN t_order_item i ON o.order_id = i.order_id) row_ WHERE rownum <= ?) WHERE rownum > ? 目前不支持rownum + BETWEEN的分页方式。 MySQL和PostgreSQL都支持LIMIT分页，无需子查询： SELECT * FROM t_order o ORDER BY id LIMIT ? OFFSET ?

数据分片--使用规范
type: item
date: 2023-06-25T08:33:00+00:00
description: 虽然 Apache ShardingSphere 希望能够完全兼容所有的SQL以及单机数据库，但分布式为数据库带来了更加复杂的场景。 Apache ShardingSphere 希望能够优先解决海量数据 OLTP 的问题，OLAP 的相关支持，会一点一点的逐渐完善。 一、SQL 支持项 路由至单数据节点 路由至多数据节点 不支持项 路由至多数据节点 对分片键进行操作 示例 支持的SQL 不支持的SQL DISTINCT支持情况详细说明 支持的SQL 不支持的SQL 1.1、支持项 1、路由至单数据节点 100%全兼容（目前仅MySQL，其他数据库完善中）。 2、路由至多数据节点 全面支持DML、DDL、DCL、TCL和部分DAL。支持分页、去重、排序、分组、聚合、关联查询（不支持跨库关联）。以下用最为复杂的DML举例： SELECT主语句 SELECT select_expr [, select_expr ...] FROM table_reference [, table_reference ...] [WHERE predicates] [GROUP BY {col_name | position} [ASC | DESC], ...] [ORDER BY {col_name | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] select_expr * | [DISTINCT] COLUMN_NAME [AS] [alias] | (MAX | MIN | SUM | AVG)(COLUMN_NAME | alias) [AS] [alias] | COUNT(* | COLUMN_NAME | alias) [AS] [alias] table_reference tbl_name [AS] alias] [index_hint_list] | table_reference ([INNER] | {LEFT|RIGHT} [OUTER]) JOIN table_factor [JOIN ON conditional_expr | USING (column_list)] 1.2、不支持项 1、路由至多数据节点 部分支持CASE WHEN CASE WHEN 中包含子查询不支持 CASE WHEN 中使用逻辑表名不支持（请使用表别名） 不支持 HAVING、UNION (ALL) 部分支持子查询 子查询中使用WHERE条件时，必须包含分片键，当外层查询中也包含分片键时，子查询和外层查询中的分片键必须保持一致 除了分页子查询的支持之外(详情请参考分页)，也支持同等模式的子查询。无论嵌套多少层，ShardingSphere都可以解析至第一个包含数据表的子查询，一旦在下层嵌套中再次找到包含数据表的子查询将直接抛出解析异常。 例如，以下子查询可以支持： SELECT COUNT(*) FROM (SELECT * FROM t_order) o; SELECT COUNT(*) FROM (SELECT * FROM t_order WHERE order_id = 1) o; SELECT COUNT(*) FROM (SELECT * FROM t_order WHERE order_id = 1) o WHERE o.order_id = 1; 以下子查询不支持： SELECT COUNT(*) FROM (SELECT * FROM t_order WHERE product_id = 1) o; SELECT COUNT(*) FROM (SELECT * FROM t_order WHERE order_id = 1) o WHERE o.order_id = 2;``` 简单来说，通过子查询进行非功能需求，在大部分情况下是可以支持的。比如分页、统计总数等；而通过子查询实现业务查询当前并不能支持。 由于归并的限制，子查询中包含聚合函数目前无法支持。 不支持包含schema的SQL。因为ShardingSphere的理念是像使用一个数据源一样使用多数据源，因此对SQL的访问都是在同一个逻辑schema之上。 2、对分片键进行操作 运算表达式和函数中的分片键会导致全路由。 假设create_time为分片键，则无法精确路由形如SQL： SELECT * FROM t_order WHERE to_date(create_time, 'yyyy-mm-dd') = '2019-01-01'; 由于ShardingSphere只能通过SQL字面提取用于分片的值，因此当分片键处于运算表达式或函数中时，Sh…

数据分片--内核剖析
type: item
date: 2023-06-25T08:25:00+00:00
description: 一、流程 ShardingSphere的3个产品的数据分片主要流程是完全一致的。 核心由 SQL解析 => 执行器优化 => SQL路由 => SQL改写 => SQL执行 => 结果归并的流程组成。 1.1、SQL解析 分为词法解析和语法解析。 先通过词法解析器将SQL拆分为一个个不可再分的单词。再使用语法解析器对SQL进行理解，并最终提炼出解析上下文。 解析上下文包括表、选择项、排序项、分组项、聚合函数、分页信息、查询条件以及可能需要修改的占位符的标记。 1.2、执行器优化 合并和优化分片条件，如OR等。 1.3、SQL路由 根据解析上下文匹配用户配置的分片策略，并生成路由路径。目前支持分片路由和广播路由。 1.4、SQL改写 将SQL改写为在真实数据库中可以正确执行的语句。SQL改写分为正确性改写和优化改写。 1.5、SQL执行 通过多线程执行器异步执行。 1.6、结果归并 将多个执行结果集归并以便于通过统一的JDBC接口输出。结果归并包括流式归并、内存归并和使用装饰者模式的追加归并这几种方式。 二、解析引擎 相对于其他编程语言，SQL是比较简单的。 不过，它依然是一门完善的编程语言，因此对SQL的语法进行解析，与解析其他编程语言（如：Java语言、C语言、Go语言等）并无本质区别。 2.1、抽象语法树 解析过程分为词法解析和语法解析。 词法解析器用于将SQL拆解为不可再分的原子符号，称为Token。并根据不同数据库方言所提供的字典，将其归类为关键字，表达式，字面量和操作符。 再使用语法解析器将SQL转换为抽象语法树。 例如，以下SQL： SELECT id, name FROM t_user WHERE status = 'ACTIVE' AND age > 18 解析之后的为抽象语法树见下图。 为了便于理解，抽象语法树中的关键字的Token用绿色表示，变量的Token用红色表示，灰色表示需要进一步拆分。 最后，通过对抽象语法树的遍历去提炼分片所需的上下文，并标记有可能需要改写的位置。 供分片使用的解析上下文包含查询选择项（Select Items）、表信息（Table）、分片条件（Sharding Condition）、自增主键信息（Auto increment Primary Key）、排序信息（Order By）、分组信息（Group By）以及分页信息（Limit、Rownum、Top）。 SQL的一次解析过程是不可逆的，一个个Token的按SQL原本的顺序依次进行解析，性能很高。 考虑到各种数据库SQL方言的异同，在解析模块提供了各类数据库的SQL方言字典。 2.2、SQL解析引擎 第三代SQL解析器则从3.0.x版本开始，ShardingSphere尝试使用ANTLR作为SQL解析的引擎，并计划根据DDL -> TCL -> DAL –> DCL -> DML –>DQL这个顺序，依次替换原有的解析引擎，目前仍处于替换迭代中。 使用ANTLR的原因是希望ShardingSphere的解析引擎能够更好的对SQL进行兼容。对于复杂的表达式、递归、子查询等语句，虽然ShardingSphere的分片核心并不关注，但是会影响对于SQL理解的友好度。 经过实例测试，ANTLR解析SQL的性能比自研的SQL解析引擎慢3-10倍左右。为了弥补这一差距，ShardingSphere将使用PreparedStatement的SQL解析的语法树放入缓存。 因此建议采用PreparedStatement这种SQL预编译的方式提升性能。 第三代SQL解析引擎的整体结构划分如下图所示。 三、路由引擎 根据解析上下文匹配数据库和表的分片策略，并生成路由路径。 对于携带分片键的SQL，根据分片键的不同可以划分为单片路由(分片键的操作符是等号)、多片路由(分片键的操作符是IN)和范围路由(分片键的操作符是BETWEEN)。 不携带分片键的SQL则采用广播路由。 分片策略通常可以采用由数据库内置或由用户方配置。 数据库内置的方案较为简单，内置的分片策略大致可分为尾数取模、哈希、范围、标签、时间等。 由用户方配置的分片策略则更加灵活，可以根据使用方需求定制复合分片策略。 如果配合数据自动迁移来使用，可以做到无需用户关注分片策略，自动由数据库中间层分片和平衡数据即可，进而做到使分布式数据库具有的弹性伸缩的能力。 在ShardingSphere的线路规划中，弹性伸缩将于4.x开启。 3.1、分片路由 用于根据分片键进行路由的场景，又细分为直接路由、标准路由和笛卡尔积路由这3种类型。 满足直接路由的条件相对苛刻，它需要通过Hint（使用HintAPI直接指定路由至库表）方式分片，并且是只分库不分表的前提下，则可以避免SQL解析和之后的结果归并。 因…

数据分片--核心概念
type: item
date: 2023-06-25T08:20:00+00:00
description: 一、SQL 1.1、逻辑表 水平拆分的数据库（表）的相同逻辑和数据结构表的总称。例：订单数据根据主键尾数拆分为10张表，分别是t_order_0到t_order_9，他们的逻辑表名为t_order。 1.2、真实表 在分片的数据库中真实存在的物理表。即上个示例中的t_order_0到t_order_9。 1.3、数据节点 数据分片的最小单元。由数据源名称和数据表组成，例：ds_0.t_order_0。 1.4、绑定表 指分片规则一致的主表和子表。例如：t_order表和t_order_item表，均按照order_id分片，则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联，关联查询效率将大大提升。举例说明，如果SQL为： SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); 在不配置绑定表关系时，假设分片键order_id将数值10路由至第0片，将数值11路由至第1片，那么路由后的SQL应该为4条，它们呈现为笛卡尔积： SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); SELECT i.* FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); SELECT i.* FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); 配置绑定表关系后，路由的SQL应该为2条： SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); 1.5、广播表 指所有的分片数据源中都存在的表，表结构和表中的数据在每个数据库中均完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景，例如：字典表。 1.6、逻辑索引 某些数据库（如：PostgreSQL）不允许同一个库存在名称相同索引，某些数据库（如：MySQL）则允许只要同一个表中不存在名称相同的索引即可。 逻辑索引用于同一个库不允许出现相同索引名称的分表场景，需要将同库不同表的索引名称改写为索引名 + 表名，改写之前的索引名称成为逻辑索引。 二、分片 2.1、分片键 用于分片的数据库字段，是将数据库(表)水平拆分的关键字段。例：将订单表中的订单主键的尾数取模分片，则订单主键为分片字段。 SQL中如果无分片字段，将执行全路由，性能较差。 除了对单分片字段的支持，ShardingSphere也支持根据多个字段进行分片。 2.2、分片算法 通过分片算法将数据分片，支持通过=、BETWEEN和IN分片。分片算法需要应用方开发者自行实现，可实现的灵活度非常高。 目前提供4种分片算法。由于分片算法和业务实现紧密相关，因此并未提供内置分片算法，而是通过分片策略将各种场景提炼出来，提供更高层级的抽象，并提供接口让应用开发者自行实现分片算法。 精确分片算法 对应PreciseShardingAlgorithm，用于处理使用单一键作为分片键的=与IN进行分片的场景。需要配合StandardShardingStrategy使用。 范围分片算法 对应RangeShardingAlgorithm，用于处理使用单一键作为分片键的BETWEEN AND进行分片的场景。需要配合StandardShardingStrategy使用。 复合分片算法 对应ComplexKeysShardingAlgorithm，用于处理使用多键作为分片键进行分片的场景，包含多个分片键的逻辑较复杂，需要应用开发者自行处理其中的复杂度。需要配合ComplexShardingStrategy使用。 Hin…

ShardingSphere简介
type: item
date: 2023-06-25T08:16:00+00:00
description: 一、概念 ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈，它由Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar这3款相互独立的产品组成。 均提供标准化的数据分片、分布式事务 和 数据库治理功能，可适用于如Java同构、异构语言、云原生等各种多样化的应用场景。 二、Sharding-JDBC 定位为轻量级Java框架，在Java的JDBC层提供的额外服务。 它使用客户端直连数据库，以jar包形式提供服务，无需额外部署和依赖，可理解为增强版的JDBC驱动，完全兼容JDBC和各种ORM框架。 适用于任何基于Java的ORM框架，如：JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。 基于任何第三方的数据库连接池，如：DBCP, C3P0, BoneCP, Druid, HikariCP等。 支持任意实现JDBC规范的数据库。目前支持MySQL，Oracle，SQLServer和PostgreSQL。 三、Sharding-Proxy 定位为透明化的数据库代理端，提供封装了数据库二进制协议的服务端版本，用于完成对异构语言的支持。 目前先提供MySQL版本，它可以使用任何兼容MySQL协议的访问客户端(如：MySQL Command Client, MySQL Workbench等)操作数据，对DBA更加友好。 向应用程序完全透明，可直接当做MySQL使用。 适用于任何兼容MySQL协议的客户端。 四、Sharding-Sidecar（TBD） 定位为Kubernetes或Mesos的云原生数据库代理，以DaemonSet的形式代理所有对数据库的访问。 通过无中心、零侵入的方案提供与数据库交互的的啮合层，即Database Mesh，又可称数据网格。 Database Mesh的关注重点在于如何将分布式的数据访问应用与数据库有机串联起来，它更加关注的是交互，是将杂乱无章的应用与数据库之间的交互有效的梳理。使用Database Mesh，访问数据库的应用和数据库终将形成一个巨大的网格体系，应用和数据库只需在网格体系中对号入座即可，它们都是被啮合层所治理的对象。 五、混合架构 Sharding-JDBC采用无中心化架构，适用于Java开发的高性能的轻量级OLTP应用；Sharding-Proxy提供静态入口以及异构语言的支持，适用于OLAP应用以及对分片数据库进行管理和运维的场景。 ShardingSphere是多接入端共同组成的生态圈。 通过混合使用Sharding-JDBC和Sharding-Proxy，并采用同一注册中心统一配置分片策略，能够灵活的搭建适用于各种场景的应用系统，架构师可以更加自由的调整适合于当前业务的最佳系统架构。 六、功能列表 6.1、数据分片 分库 & 分表 读写分离 分片策略定制化 无中心化分布式主键 6.2、分布式事务 标准化事务接口 XA强一致事务 柔性事务 6.3、数据库治理 配置动态化 编排 & 治理 数据脱敏 可视化链路追踪 弹性伸缩(规划中)

分库分表概述
type: item
date: 2023-06-25T08:06:00+00:00
description: 一、问题 为什么要分库分表（设计高并发系统的时候，数据库层面该如何设计）？ 用过哪些分库分表中间件？不同的分库分表中间件都有什么优点和缺点？ 具体是如何对数据库如何进行垂直拆分或水平拆分的？ 二、为什么要分库分表(设计高并发系统的时候，数据库层面该如何设计？) 每天活跃用户数上千万，每天单表新增数据多达 50 万，一个表总数据量都已经达到了两三千万。 数据库磁盘容量不断消耗掉，高峰期并发达到惊人的 5000~8000 。 三、分表 单表数据量太大，会极大影响 sql 执行的性能。单表到几百万的时候，性能就会相对差一些了，需要分表了。 分表：把一个表的数据放到多个表中，查询的时候就查一个表。 比如按照用户 id 来分表，将一个用户的数据就放在一个表中。然后操作的时候你对一个用户就操作那个表就好了。 这样可以控制每个表的数据量在可控的范围内，比如每个表就固定在 200 万以内。 四、分库 一个数据库最多支撑并发 2000，需要扩容，而且一个健康的单库并发值最好保持在每秒 1000 左右，不要太大。 可以将一个库的数据拆分到多个库中，访问的时候就访问一个库。 | # | 分库分表前 | 分库分表后 | | ------------ | ---------------------------- | -------------------------------------------- | | 并发支撑情况 | MySQL 单机部署，扛不住高并发 | MySQL 从单机到多机，能承受的并发增加了多倍 | | 磁盘使用情况 | MySQL 单机磁盘容量几乎撑满 | 拆分为多个库，数据库服务器磁盘使用率大大降低 | | SQL 执行性能 | 单表数据量太大，SQL 越跑越慢 | 单表数据量减少，SQL 执行效率明显提升 | 五、分库分表中间件 常见中间件： Cobar TDDL Atlas Sharding-jdbc Mycat 5.1、Cobar 阿里 b2b 团队开发和开源的，属于 proxy 层方案，就是介于应用服务器和数据库服务器之间。应用程序通过 JDBC 驱动访问 Cobar 集群，Cobar 根据 SQL 和分库规则对 SQL 做分解，然后分发到 MySQL 集群不同的数据库实例上执行。早些年还可以用，但是最近几年都没更新了，基本没啥人用，差不多算是被抛弃的状态吧。而且不支持读写分离、存储过程、跨库 join 和分页等操作。 5.2、TDDL 淘宝团队开发的，属于 client 层方案。支持基本的 crud 语法和读写分离，但不支持 join、多表查询等语法。目前使用的也不多，因为还依赖淘宝的 diamond 配置管理系统。 5.3、Atlas 360 开源的，属于 proxy 层方案，以前是有一些公司在用的，但是确实有一个很大的问题就是社区最新的维护都在 5 年前了。所以，现在用的公司基本也很少了。 5.4、Sharding-jdbc 当当开源的，属于 client 层方案，是 ShardingSphere 的 client 层方案， ShardingSphere 还提供 proxy 层的方案 Sharding-Proxy。确实之前用的还比较多一些，因为 SQL 语法支持也比较多，没有太多限制，而且截至 2019.4，已经推出到了 4.0.0-RC1 版本，支持分库分表、读写分离、分布式 id 生成、柔性事务（最大努力送达型事务、TCC 事务）。而且确实之前使用的公司会比较多一些（这个在官网有登记使用的公司，可以看到从 2017 年一直到现在，是有不少公司在用的），目前社区也还一直在开发和维护，还算是比较活跃，个人认为算是一个现在也可以选择的方案。 5.5、Mycat 基于 Cobar 改造的，属于 proxy 层方案，支持的功能非常完善，而且目前应该是非常火的而且不断流行的数据库中间件，社区很活跃，也有一些公司开始在用了。但是确实相比于 Sharding jdbc 来说，年轻一些，经历的锤炼少一些。 六、总结 综上，现在其实建议考量的，就是 Sharding-jdbc 和 Mycat，这两个都可以去考虑使用。 Sharding-jdbc 这种 client 层方案的优点在于不用部署，运维成本低，不需要代理层的二次转发请求，性能很高，但是如果遇到升级啥的需要各个系统都重新升级版本再发布，各个系统都需要耦合 Sharding-jdbc 的依赖； Mycat 这种 proxy 层方案的缺点在于需要部署，自己运维一套中间件，运维成本高，但是好处在于对于各个项目是透明的，如果遇到升级之类的都是自己中间件那里搞就行了。 通常来说，这两个方案其实都可以选用，但是我个人建议中小型公司选用 Sharding-jdbc，client 层方案…