ToB企服应用市场:ToB评测及商务社交产业平台

标题: 分布式数据库 Join 查询设计与实现浅析 [打印本页]

作者: 吴旭华    时间: 2023-6-9 10:57
标题: 分布式数据库 Join 查询设计与实现浅析
相对于单例数据库的查询操作,分布式数据查询会有很多技术难题。
本文记录 Mysql 分库分表 和 Elasticsearch Join 查询的实现思路,了解分布式场景数据处理的设计方案。
文章从常用的关系型数据库 MySQL 的分库分表Join 分析,再到非关系型 ElasticSearch 来分析 Join 实现策略。逐步深入Join 的实现机制。
①Mysql 分库分表 Join 查询场景

分库分表场景下,查询语句如何分发,数据如何组织。相较于NoSQL 数据库,Mysql 在SQL 规范的范围内,相对比较容易适配分布式场景。
基于 sharding-jdbc 中间件的方案,了解整个设计思路。
sharding-jdbc

Code Insight

示例代码工程:git@github.com:cluoHeadon/sharding-jdbc-demo.git
  1. /**
  2. * 执行查询 SQL 切入点,从这里可以完整 debug 执行流程
  3. * @see ShardingPreparedStatement#execute()
  4. * @see ParsingSQLRouter#route(String, List, SQLStatement) Join 查询实际涉及哪些表,就是在路由规则里匹配得出来的。
  5. */
  6. public boolean execute() throws SQLException {
  7.     try {
  8.         // 根据参数(决定分片)和具体的SQL 来匹配相关的实际 Table。
  9.         Collection<PreparedStatementUnit> preparedStatementUnits = route();
  10.         // 使用线程池,分发执行和结果归并。
  11.         return new PreparedStatementExecutor(getConnection().getShardingContext().getExecutorEngine(), routeResult.getSqlStatement().getType(), preparedStatementUnits).execute();
  12.     } finally {
  13.         JDBCShardingRefreshHandler.build(routeResult, connection).execute();
  14.         clearBatch();
  15.     }
  16. }
复制代码
SQL 路由策略

启用 sql 打印,直观看到实际分发执行的 SQL
  1. # 打印的代码,就是在上述route 得出 ExecutionUnits 后,打印的
  2. sharding.jdbc.config.sharding.props.sql.show=true
复制代码
sharding-jdbc 根据不同的SQL 语句,会有不同的路由策略。我们关注的 Join 查询,实际相关就是以下两种策略。
  1. -- 参数不明,不能定位分片的情况
  2. select * from order o inner join order_item oi on o.order_id = oi.order_id
  3. -- 路由结果
  4. -- Actual SQL: db1 ::: select * from order_1 o inner join order_item_1 oi on o.order_id = oi.order_id
  5. -- Actual SQL: db1 ::: select * from order_1 o inner join order_item_0 oi on o.order_id = oi.order_id
  6. -- Actual SQL: db1 ::: select * from order_0 o inner join order_item_1 oi on o.order_id = oi.order_id
  7. -- Actual SQL: db1 ::: select * from order_0 o inner join order_item_0 oi on o.order_id = oi.order_id
  8. -- Actual SQL: db0 ::: select * from order_1 o inner join order_item_1 oi on o.order_id = oi.order_id
  9. -- Actual SQL: db0 ::: select * from order_1 o inner join order_item_0 oi on o.order_id = oi.order_id
  10. -- Actual SQL: db0 ::: select * from order_0 o inner join order_item_1 oi on o.order_id = oi.order_id
  11. -- Actual SQL: db0 ::: select * from order_0 o inner join order_item_0 oi on o.order_id = oi.order_id
复制代码
②Elasticsearch Join 查询场景

首先,对于 NoSQL 数据库,要求 Join 查询,可以考虑是不是使用场景和用法有问题。
然后,不可避免的,有些场景需要这个功能。Join 查询的实现更贴近SQL 引擎。
基于 elasticsearch-sql 组件的方案,了解大概的实现思路。
elasticsearch-sql

Code Insight

源码地址:git@github.com:NLPchina/elasticsearch-sql.git
  1. /**
  2. * Execute the ActionRequest and returns the REST response using the channel.
  3. * @see ElasticDefaultRestExecutor#execute
  4. * @see ESJoinQueryActionFactory#createJoinAction Join 算法选择
  5. */
  6. @Override
  7. public void execute(Client client, Map<String, String> params, QueryAction queryAction, RestChannel channel) throws Exception{
  8.     // sql parse
  9.     SqlElasticRequestBuilder requestBuilder = queryAction.explain();
  10.     // join 查询
  11.     if(requestBuilder instanceof JoinRequestBuilder){
  12.         // join 算法选择。包括:HashJoinElasticExecutor、NestedLoopsElasticExecutor
  13.         // 如果关联条件为等值(Condition.OPEAR.EQ),则使用 HashJoinElasticExecutor
  14.         ElasticJoinExecutor executor = ElasticJoinExecutor.createJoinExecutor(client,requestBuilder);
  15.         executor.run();
  16.         executor.sendResponse(channel);
  17.     }
  18.     // 其他类型查询 ...
  19. }
复制代码
③More Than Join

Join 算法

  1. EXPLAIN FORMAT=JSON  
  2. SELECT * FROM
  3.     sale_line_info u
  4.     JOIN sale_line_manager o ON u.sale_line_code = o.sale_line_code;
复制代码
  1. {
  2.     "query_block": {
  3.         "select_id": 1,
  4.         // 使用的join 算法: nested_loop
  5.         "nested_loop": [
  6.             // 涉及join 的表以及对应的 key,其他的信息与常用explain 类似
  7.             {
  8.                 "table": {
  9.                     "table_name": "o",
  10.                     "access_type": "ALL"
  11.                 }
  12.             },
  13.             {
  14.                 "table": {
  15.                     "table_name": "u",
  16.                     "access_type": "ref"
  17.                 }
  18.             }
  19.         ]
  20.     }
  21. }
复制代码
Elasticsearch Nested类型

分析Elasticsearch 业务数据以及使用场景,还有一种选择是直接存储关联信息的文档。在 Elasticsearch 中,是以完整文档形式提供查询和检索,彻底避开使用 Join 相关的技术。
这样就牵扯到关联是归属类型的数据还是公用类型的数据、关联数据量的大小、关联数据的更新频率等。这些都是使用 Nested 类型需要考虑的因素。
更多的使用方法,可以从网上和官网找到,不做赘述。
我们现在有个业务功能正好使用到 Nested类型, 在查询和优化过程中,解决了非常大的难题。
总结

通过运行原理分析,对于运行流程有了清晰和深入的认知。
对于中间件的优化和技术选型更加有目的性,使用上会更加谨慎和小心。
明确的筛选条件,更小的筛选范围,limit 取值数据,都可以减少计算陈本,提高性能。
参考

作者:京东物流 杨攀
来源:京东云开发者社区

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4