写点什么

跨库分页

作者:zarmnosaj
  • 2022-10-25
    四川
  • 本文字数:1247 字

    阅读完需:约 4 分钟

背景

最近有个开发需求,是跨库分页,并且两个库的表结构不是一样的,一个是 mysql 的关系型结构,另一个是 dataware 的宽表数据。初步搜索了一下,暂时没有发现有中间件或者框架支持这种查询,但是中间搜索到有些思路值得记录,并且目前的做法是基于代码在内存中做分页返回。

条件

假设 mysql 中有三张表,结构是:

**student**

| name |

| --- |

| id |

| stu_name |


**course**

| name |

| --- |

| id |

| course_name |


**student_course**

| name |

| --- |

| id |

| stu_id |

| course_id |


另外,dataware 中的表结构是:

**student_course**

| name |

| --- |

| id |

| stu_id |

| stu_name |

| course_id |

| course_name |


需求

将两个不同数据库中的数据,查询啊、学生信息及学生包含的所有选课信息进行分页,例如展示为:


stu_id=1,stu_name=小明,course_id=1,course_name=科学


stu_id=1,stu_name=小明,course_id=2,course_name=数学


stu_id=2,stu_name=小美,course_id=1,course_name=科学


stu_id=2,stu_name=小美,course_id=3,course_name=英语


......

分析

如果是单库单表,可以直接使用现有的框架,例如 mybatis-plus 的分页插件进行分页,或者自行实现拦截器,在 SQL 中根据分页参数,拼接 limit 进行查询。


如果是单库多表,可以考虑将两个表的查询写在一个 SQL 中,用 union 联结查询结果,然后对总的查询结果进行分页,同样的可以使用 mybatis-plus 插件或者自行实现。


如果是多库多表,也就是跨库查询分页,则需要将两个库的查询结果进行联合分页,如何做?是个问题。

方案

方案 1

根据查询条件在每个库中都查询出符合条件的数据,然后将数据组装在一起,对组装的结果集,使用参数中的页码、页大小进行分页、筛选数据,相当于是内存分页。


此方案实现的难度最低,逻辑最简单,但是弊端也很明显,因为是基于内存做的分页,而且查询每次都需要将符合条件的所有数据查询出来,当查询到第 100 页的时候,按理说只需要第 100 页的数据,但是按照此方案的思路,需要将 100 页之前的数据也全部查询出来,甚至 100 页之后的所有数据也需要查询出来。

方案 2

假设结果需要按照数据创建时间排序,页面大小为 10,第一次查询为第一页,相当于单表的 limit 0,10,此时对每个数据库都根据条件查询、且根据时间排序,选择 limit0,10 的数据,然后将最多 20 条的数据聚合起来,进行内存分页。


当查询第二页时,相当于单表的 offset 10 limit 10,此时需要分页参数以外,还需要传入上一次查询获得的最大时间,此时则在每个数据库中分别查询数据时间>=传入时间的数据,且带上限制条件 limit 0,10(每个数据库都查询 10 条),因为有可能有极端情况:当前查询的页数据都只存在于一个库中,然后再将两个数据库的查询结果联结分页(基于内存)。


此种方案的限制条件很明显,就是在查询除了第一页之外的操作时,都需要传入时间(排序基准值),有此种限制存在时,则不能允许跳页的情况存在,因为随便选取一页并不能知道排序基准值是多少,否则又会回到方案 1 的情况,将所有数据查询出来在内存中做分页。

其他方案

待想到或有其他好的建议时再补充......

发布于: 刚刚阅读数: 3
用户头像

zarmnosaj

关注

靡不有初,鲜克有终 2020-02-06 加入

成都后端

评论

发布
暂无评论
跨库分页_10月月更_zarmnosaj_InfoQ写作社区