Java猿社區—ShardingSphere之跨庫分頁帶來的性能問題與常用解決辦法
文章目錄
參考:
ShardingSphere中文文檔
假設頁大小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作爲下次查詢條件
的分頁方式等。
使用上次分頁數據結尾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 ?