mysql的分页怎么用 mysql分页查询原理( 二 )


不过光标分页的好处是在任何数量的页面上都很迅速 。它也很适合无限滚动,在这种情况下,页面首先不需要可以直接寻址 。
Laravel文档中有一些关于偏移量和游标之间的权衡的好的背景 。
cursor -vs-offset-pagination
考虑到所有这些,让我们来看看一个偏移/限制优化,可以使它的性能足以在成千上万的页面上使用 。
使用递延join的Offset/Limit
递延连接(deferred join )是一种技术,它将对要求的列的访问推迟到应用了偏移量和限制之后 。
使用这种技术,我们创建一个内部查询,可以用特定的索引进行优化,以获得最大的速度,然后将结果连接到同一个表,以获取完整的行 。
它看起来像这样:
这种方法的好处可以根据你的数据集有很大的不同,但是这种方法允许数据库尽可能少地检查数据 , 以满足用户的意图 。
查询中 "昂贵的 "select *部分只在与内部查询相匹配的15条记录上运行 。所有数据的Select都被推迟了,因此被称为推迟join 。
这种方法不太可能比传统的偏移/限制性能差,尽管它是可能的,所以一定要在你的数据上进行测试!
Laravel实现
我们如何把这一点带到我们最喜欢的网络框架,如Laravel和Rails?
让我们具体看看Laravel,因为我不知道Rails 。
感谢Laravel的macroable特性,我们可以扩展Eloquent Query Builder来添加一个新的方法,叫做deferredPaginate 。为了保持一致性,我们将模仿常规分页的签名 。
我们将尝试做尽可能少的自定义工作 , 并将大部分工作留给 Laravel 。
这是我们要做的:
这应该为我们提供 LaravelLengthAwarePaginator 和延迟连接的所有好处!
一个Github仓库
递延Join和覆盖索引
还没有完成...
使用递延Join的主要好处是减少了数据库必须检索然后丢弃的数据量 。我们可以通过帮助数据库获得它需要的数据而更进一步,而无需获取底层行 。
这样做的方法称为“覆盖索引covering index”,它是确保快速偏移/限制分页的最终解决方案 。
覆盖索引是一个索引,在这个索引中,查询的所有需要的字段都包含在索引本身中 。当一个查询的所有部分都能被一个索引 "覆盖 "时,数据库根本不需要读取该行,它可以从索引中获得它需要的一切 。
请注意,覆盖索引并不是以任何特殊方式创建的 。它只是指一个索引满足了一个查询所需要的一切的情况 。一个查询上的覆盖索引很可能不是另一个查询上的覆盖索引 。
在接下来的几个例子中 , 我们将使用这个基本的表 , 我把它填满了~1000万条记录 。
让我们看一个仅select索引列的简单查询 。在这种情况下,我们将从email表中进行select contacts 。
在这种情况下,数据库根本不需要读取基础行 。在MySQL中,我们可以通过运行一个解释并查看额外的列来验证这一点:
extra: using index告诉我们 , MySQL能够只使用索引来满足整个查询,而不看基础行 。
如果尝试select name from contacts limit 10 ,  我们将期望MySQL必须到该行去获取数据,因为名字name没有被索引 。这正是发生的情况,由下面的解释显示 。
extra不再显示 using index,所以我们没有使用覆盖索引 。
假设你每页有15条记录,你的用户想查看第1001页,你的内部查询最终会是这样的 。
select id from contacts order by id limit 15 OFFSET 150000
explain结果显示:
MySQL能够单看索引来执行这个查询 。它不会简单地跳过前15万行,在使用offset是没有办法的,但它不需要读取15万行 。(只有游标分页可以让你跳过所有的行) 。

推荐阅读