Java猿社区—ShardingSphere之跨库分页带来的性能问题与常用解决办法

Java猿社区—ShardingSphere之跨库分页带来的性能问题与常用解决办法


参考:
ShardingSphere中文文档

分库分表的几种常见玩法及如何解决跨库查询等问题

一次shardingjdbc踩坑引起的胡思乱想

业界难题-“跨库分页”的四种方案

假设页大小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;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-baIGWOGp-1584131315424)(evernotecid://6438F78B-FBEF-42D1-A152-F4935CA4BBB8/appyinxiangcom/15654258/ENResource/p11787)]

数据库端的查询压力都是差不多的, 因为都是要差不多要扫描1010行才能取得到数据. 不同的是改写sql后, 客户端的内存消耗和网络消耗变大了.
shardingsphere巧妙地利用流式处理和优先级队列结合的方式(“流式归并”),消除了客户端内存消耗的压力, 但是网络消耗的影响依然是无法消除.

如何避免使用limit带来的效率问题呢

有很多方法可以避免使用LIMIT进行分页。比如构建行记录数量与行偏移量的二级索引,或使用上次分页数据结尾ID作为下次查询条件的分页方式等。

使用上次分页数据结尾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;

同理,使用上次分页数据结尾的时间戳作为下次查询条件也可以(按照时间进行排序)。

二次查询法

这种方法能够满足业务的精确需要,无需业务折衷,又高性能的方法,缺点是业务代码复杂且需要进行两次数据库查询。

请移步到:业界难题-“跨库分页”的四种方案

分页子查询(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

MySQL和PostgreSQL都支持LIMIT分页,无需子查询:

SELECT * FROM t_order o ORDER BY id LIMIT ? OFFSET ?
欢迎加入Java猿社区!
免费领取我历年收集的所有学习资料哦!

欢迎加入Java猿社区.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章