一、分页查询的那些事儿

咱们做开发的,谁还没写过几个分页查询呢?传统的LIMIT OFFSET方案简单直接,就像去书店买书,跟店员说"我要第100页的10本书",店员就得吭哧吭哧数到第100页再给你拿——效率可想而知。

-- 传统分页查询示例(KingbaseES语法)
SELECT * FROM orders 
ORDER BY create_time DESC
LIMIT 10 OFFSET 100;  -- 获取第11页数据(每页10条)

当数据量超过10万条时,这种写法就会暴露出致命缺陷:OFFSET越大,数据库越要扫描并丢弃前面的所有行,就像让你从100层高的楼上往下跳,每层都要踩一脚缓冲,最后10层反而最费劲。

二、键集分页的救赎之道

键集分页(Keyset Pagination)的精髓在于:记住上次看到的最后一条记录,下次直接从它后面开始查。这就像书签,不需要知道当前是第几页,只需要记住上次读到哪里。

-- 键集分页示例(假设上次最后一条记录的create_time是'2023-06-20 15:30:00')
SELECT * FROM orders 
WHERE create_time < '2023-06-20 15:30:00'  -- 关键条件
ORDER BY create_time DESC 
LIMIT 10;  -- 不需要OFFSET

注意三个要点:

  1. 排序字段必须有索引(如create_time上的索引)
  2. WHERE条件必须与ORDER BY方向匹配(这里是<对应DESC
  3. 排序字段需唯一(否则需添加主键作为第二排序条件)

三、实战中的进阶技巧

3.1 多字段排序场景

当你的分页需要按多个字段排序时(比如先按分类再按时间),键集分页需要更精细的处理:

-- 多字段键集分页(上次最后记录:category=5, create_time='2023-06-20 15:30:00')
SELECT * FROM products 
WHERE (category = 5 AND create_time < '2023-06-20 15:30:00') 
   OR (category < 5)
ORDER BY category DESC, create_time DESC 
LIMIT 10;

3.2 性能对比测试

我们在KingbaseES中构造100万条测试数据,对比两种方案的执行计划:

-- 传统分页(执行时间:1200ms)
EXPLAIN ANALYZE 
SELECT * FROM large_table 
ORDER BY id 
LIMIT 10 OFFSET 999990;

-- 键集分页(执行时间:3ms)
EXPLAIN ANALYZE 
SELECT * FROM large_table 
WHERE id > 999990 
ORDER BY id 
LIMIT 10;

键集分页的魔法在于:它可以直接利用索引定位,而不用遍历前面的数据。就像用GPS直接导航到目的地,而不是从起点开始数路口。

四、避坑指南与最佳实践

  1. 索引是前提:没有合适的索引,键集分页也会失效。建议为所有排序字段建立复合索引:

    CREATE INDEX idx_orders_created ON orders(create_time DESC);
    
  2. 边界情况处理

    • 第一页:不需要WHERE条件
    • 最后一页:结果不足LIMIT数量时停止加载
    • 新增数据可能导致"跳页"(这是特性不是bug)
  3. 前端配合:需要将每页最后的记录值传给后端:

    // 前端示例(React)
    const loadNextPage = (lastItem) => {
      axios.get('/api/orders', {
        params: { last_time: lastItem.createTime }
      })
    }
    
  4. KingbaseES特有优化:可以利用FETCH FIRST...ONLY语法:

    SELECT * FROM orders
    WHERE create_time < :last_time
    ORDER BY create_time DESC
    FETCH FIRST 10 ROWS ONLY;  -- KingbaseES特色语法
    

五、什么时候该用哪种方案

  • 用传统分页

    • 需要显示总页数(需配合COUNT查询)
    • 允许随机跳页(如直接跳到第50页)
    • 数据量小于1万条时
  • 用键集分页

    • 无限滚动加载(如社交动态)
    • 大数据量下的分页(10万条以上)
    • 排序字段有索引时

记住:所有技术方案都是权衡的结果。键集分页牺牲了随机访问能力,换来了线性访问的性能飞跃。就像电梯虽然不能停靠所有楼层,但比楼梯快多了不是吗?

六、总结

LIMIT OFFSET到键集分页的升级,本质上是从"数数式"查询到"导航式"查询的转变。在KingbaseES这样的国产数据库中,合理利用键集分页可以轻松应对百万级数据的分页需求。下次当你看到分页查询变慢时,不妨试试这个"书签大法",可能会收获意想不到的性能提升!