优质博文:IT-BLOG-CN
假如业务上须要实行如下分页查询,Sharding-JDBC怎样实行分页查询的? 官方文档
- select * from student_time ORDER BY create_time ASC limit 1000, 5;
复制代码 Sharding-JDBC分页查询时在每个分表中都查询1005条数据,然后在内存中排序,但问题是分页越大,数据量就越多,就会导致内存溢出。Sharding-JDBC对于归并排序做了很好的优化,但是照旧须要传输1005条非常大的数据量,查询也非常耗时。
我们先看看Sharding-JDBC中对分页做的优化:
【1】采用流式处置惩罚 + 归并排序: 制止内存的过量占用。由于SQL改写不可制止的占用了额外的带宽,但并不会导致内存暴涨。 与直觉不同,大多数人认为Sharding-JDBC会将1,000,010 * 2记录全部加载至内存,进而占用大量内存而导致内存溢出。 但由于每个效果集的记录是有序的,因此Sharding-JDBC每次仅获取各个分片的当前效果集记录,驻留在内存中的记录仅为当前路由到的分片的效果集的当前游标指向而已。 对于本身即有序的待排序对象,归并排序的时间复杂度仅为O(n),性能消耗很小。
Sharding-JDBC分片查询流程:
1、从各个数据节点获取对应的数据集;
2、将数据集举行组合/归并末了得到一个符合预期的效果集;
3、将正确的数据集返回;
Sharding-JDBC的归并由归并引擎负责,归并引擎提供了三种归并方式:
1、流式归并: 流式归并是指每一次从效果会合获取到的数据都能够通过逐条获取的方式返回正确的单条数据,他与数据库原生的返回效果集的方式最为契合。遍历、排序以及流式分组都属于流失归并的一种。
由于流式归并是从数据库中返回的效果集是逐条返回的,并不须要将全部的数据一次性加载至内存中,因此,在举行效果归并时,相沿数据库返回效果集的方式举行归并,能够极大镌汰内存的消耗,是归并方式的优先选择。
优点:
节省内存: 流式处置惩罚答应在内存中只保留当前处置惩罚的数据,而不是将整个效果集加载到内存中。这对于处置惩罚大数据集非常有利,由于它制止了内存溢出的问题。
实时性: 流式处置惩罚可以在数据还在传输的过程中开始处置惩罚,如许可以镌汰等候时间,进步查询的实时性。
缺点:
长连接占用资源: 每次只获取一条数据会导致数据库连接长时间占用,大概会消耗更多的数据库连接资源,特别是在并发查询较多的环境下。
性能开销: 每次获取一条数据须要多次网络来回,这大概会增加网络开销和延迟,特别是在高延迟网络环境中。
2、内存归并: 内存归并则是须要将效果集的全部数据都遍历并存储在内存中,再通过同一的分组、排序以及聚合等盘算之后,再将其封装成为逐条访问的数据效果集返回。
3、装饰者归并: 装饰者归并是对全部的效果集归并举行同一的功能加强,目前装饰者归并有分页归并和聚合归并这2种范例。
流失归并的原理
ShardingJDBC的流式处置惩罚和JDBC的ResultSet的原理是一样的,主要是通过和数据库保持长连接,每次next都只取当前游标地点位置的一条数据,然后在内存中举行归并。
具体流程如下: 假设user表分为db0: user_0,db1: user_1, db2: user_2三张表
1、当举行分页查询时,会将查询语句下发到三个数据源分别举行获取:
2、数据源实行了sql后,并不会将查询到的数据集直接返回给客户端,而是先将效果集存储在数据源本地,等候client通过游标一条条读取。每一个表都会维护一个自己表的游标,初始位置为第一条记录。
3、每一轮都只传输游标当前指向的记录,client会将接收到的记录加入优先级队列,第一轮的时间client维护的优先级队列如下所示。优先级队列是按照sql要求的排序字段排序。
4、优先级队列队首出队到优先级队列PriorityQueue,会实行next,去对应的db中取下一条记录,此时数据源维护的游标要向下移动一格。上述例子中,便会去user_1中取出下一条记录,再重新入队举行排序,第二轮的效果如下图所示。
出队的数据存在那里?
内存缓冲区: 当查询效果从各个分片返回时,Sharding-JDBC会将这些效果暂时存储在内存缓冲区中。在调用next()方法时,从缓冲区中获取下一条记录并返回给调用者。这种方式确保了数据在内存中是可用的,直到被处置惩罚完毕。
归并和排序: 在分页查询过程中,Sharding-JDBC会将来自不同分片的效果集举行归并和排序。归并和排序后的效果集也会暂时存储在内存中,以便在调用next()方法时能够次序返回正确的记录。
游标位置: 游标会记录当前的位置,以便在调用next()时能够正确返回下一条记录。这种机制确保了分页查询的次序性和同等性。
暂时存储: 在某些环境下,假如查询效果集非常大,内存不足以存储全部数据,Sharding-JDBC大概会使用暂时文件或其他形式的暂时存储来保存部分效果集。如许可以制止内存溢出问题,但会捐躯一些性能。
在Sharding-JDBC的分页查询过程中,数据通常会暂时存储在内存缓冲区中,直到被处置惩罚完毕。假如内存不足,大概会使用暂时存储来保存部分数据。游标记录当前的位置,以确保能够次序返回正确的记录。
5、优先级队列操作next的同时,内部维护了一个rowNumber,用来表现当前记录是第几个,每次取next时,都会+1,源码部分如下:
- public boolean next() throws SQLException {
- if (this.skipAll) {
- return false;
- } else if (this.limit.getRowCountValue < 0) {
- return this.getMergerdResult().next();
- } else {
- return ++this.rowNumber <= this.limit.getRowCountValue() && this.getMergedResult().next();
- }
- }
复制代码 limit分页的时间,便是通过这个字段找到对应开始的记录,开始拼接有用的效果集。
【2】Sharding-JDBC对仅落至单分片的查询举行进一步优化。 落至单分片查询的请求并不须要改写SQL也可以保证记录的正确性,因此在此种环境下,Sharding-JDBC并未举行SQL改写,从而达到节省带宽的目的。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |