数据库查询之游标分页

1 定义

  • 普通分页:常用的基于偏移量的分页,使用LIMITOFFSET来获取分页数据
//返回第50~60行数据
SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 50;
  • 游标分页:通过唯一的、有序的字段(游标)来标记分页的起始位置,每次分页查询时候使用'>'‘<’某个特定游标值实现分页。
//id为游标
SELECT * FROM users WHERE id>1 ORDER BY id LIMIT 10;

如果上面这条sql查出来的最后一条数据id=14,那么下一次游标分页查询sql为:

SELECT * FROM users WHERE id>14 ORDER BY id LIMIT 10;

2 为什么使用游标分页?

普通分页查询时候需要进行全表扫描,先找到前OFFSET条数据(计数),再找到其后LIMIT条数据,因为普通分页时在扫描到叶子节点之前,是不知道某个中间节点底下有多少叶子节点的,所以才需要每次都扫到叶子节点进行计数。显然当数据量特别大时,查询的速度会非常慢。

游标分页就是为了解决这个问题,它期望能够直接定位到第OFFSET条数据(不用计数),然后往后取出LIMIT条数据就可以,下次再使用最后一条数据作为游标再取出LIMIT条数据即可实现分页。

那么在数据量很大的时候,游标分页要怎么进行直接快速定位呢?——对游标的要求是使用唯一的、有序的字段,然后使用'>'‘<’来进行定位。通常使用索引作为游标,索引文件使用B+树组织,因此在进行游标分页使用索引字段'>''<'某个值的时候可以利用B+树特性进行快速定位,而不需要像普通分页那些记录扫描过的条目数。

3 游标的选择?

如果不唯一或不有序会产生什么结果呢?

  • 游标不唯一:如果表中游标列相同的数据高于LIMIT,数据检索可能产生遗漏。
    比如游标为id(非唯一索引),LIMIT=50id=6的条目数为70。如果当前sql的游标定位条件为id>5且筛选出的最后一条数据id=6(最多筛选出50id=6的数据),那么下一次游标会更新为6,定位条件为id>6,这样会有一部分id=6的数据(至少20条)被遗漏。
  • 游标无序/使用非索引字段作为游标:无法利用索引文件进行快速定位,定位时需要进行全表扫描找到游标值,然后可能还需要进一步回表去查要返回的数据,同时分页结果可能紊乱,无法得到想要的结果,查询效率也比普通分页更低。

因此选择游标时候尽量选择唯一且有序的游标,可以使用主键进行查询。当主键为一个或多个字段时(无论是数值还是字符串),都可以直接使用'>'‘<’(注意不能使用'>='‘<=’,否则数据会被重复筛选出)进行筛选:

//1. 主键为数值
SELECT * FROM users WHERE id>1 ORDER BY id LIMIT 10;
//2. 主键为字符串,字符串可以直接比较,每次查出来的最后一条数据的游标列值作为新的游标,与数值一样
SELECT * FROM users WHERE id_code>'1023' ORDER BY id_codeLIMIT 10;
//3. 主键为联合索引
SELECT * FROM users WHERE (id,id_code)>(1,'1023') ORDER BY id,id_code LIMIT 10;

你可能感兴趣的:(数据库,sql,mysql)