offset指示数据库跳过查询的前N个结果。但是,数据库仍必须从磁盘中获取这些行并将它们按顺序排列,然后才能发送以下行。
…首先根据< order by子句>对行进行排序然后通过删除< result offset子句>中指定的行数来进行限制。从最开始…
这里最关键的一点是offset仅需要一个参数:要删除的行数。没有更多的上下文。数据库唯一可以使用此数字的方法是提取和删除那么多行。换句话说,无论SQL还是N Q S L,大的偏移量都会在数据库上增加很多工作。
但是偏移问题并不仅限于此:想一想如果在获取两个页面之间插入新行会发生什么情况?
当使用offset➌跳过先前提取的条目❶时,如果在提取两个页面之间插入了新行➋,则会得到重复。也可能存在其他异常,这只是最常见的一种。
这甚至不是数据库问题,而是框架实现分页的方式:它们只是说要提取哪个页号或跳过多少行。仅凭此信息,任何数据库都无法做得更好。
这些方法共有的根本问题是它们只提供了许多要删除的行,而没有更多的上下文。在本文中,我将使用offset来指代任何这些方法。
现在想象一个没有这些问题的世界。事实证明,没有偏移的生活非常简单:只需使用where子句,仅选择您尚未看到的数据即可。
为此,我们利用了一个有序集合这一事实,即您确实有一个order by子句,不是吗?一旦有了确定的排序顺序,我们就可以使用简单的过滤器来选择最后看到的条目后面的内容:
SELECT ... FROM ... WHERE ... AND ID< ?last_seen_id ORDER BY ID DESC仅获取前10行
这是基本的食谱。当对多列进行排序时,它变得更加有趣,但是想法是相同的。此配方也适用于许多N Q S L系统。
这种方法(称为搜索方法或键集分页)解决了如上所述的结果漂移问题,甚至比偏移更快。如果您想了解使用偏移量或键集分页时数据库内部发生的情况,请查看以下幻灯片(基准,基准!):
在幻灯片43上,您还可以看到键集分页有一些限制:最值得注意的是,您不能直接导航到任意页面。但是,使用无限滚动时这不是问题。无论如何,显示要单击的页码都是糟糕的导航界面-IMHO。
如果您想了解有关如何在SQL中正确实现键集分页的更多信息,请阅读本文。即使您不参与SQL,也应该在开始实施任何内容之前先阅读该文章。
首选偏移而不是键集分页的主要原因是缺少工具支持。大多数工具都提供基于偏移量的分页,但是没有提供使用键集分页的任何便捷方法。
请注意,键集分页会影响整个技术堆栈,直到在浏览器中运行的JavaScript进行AJAX无限滚动:您必须将完整的键集(通常为多列)传递给服务器,而不是将简单的页码传递给服务器。
这是我需要您帮助的地方。如果您正在维护某种与分页有关的框架,请问您,我恳请您也为键集分页建立本机支持。如果您对详细信息有任何疑问,我们很乐意为您提供帮助(论坛,联系表,Twitter)!
即使您只是在使用应支持键集分页的软件(例如内容管理系统或网上商店),也要让维护者知道这一点。您可能只提交了功能请求(链接到此页面),或者,如果可能的话,提供了补丁程序。同样,我很乐意帮助您正确处理细节。
键集分页的问题不是技术问题。问题在于它在该领域鲜为人知并且没有工具支持。如果您喜欢无偏移分页的想法,请帮助推广。发推,分享,邮寄,您甚至可以重新博客此帖子(CC-BY-NC-ND)。也欢迎翻译,请事先与我联系-我还将在此页面上提供指向翻译的链接!
哦,而且如果您是博客用户,也可以在博客上添加横幅,以使读者意识到这一点。我准备了具有一些常见横幅格式的NoOffset横幅库。只要选择最适合您的。