不再需要担心数据库性能优化的日子已经一去不复返了。
随着时代的发展,每个新企业家都希望建立下一个Facebook,并结合收集每个可能的数据点以提供更好的机器学习预测的心态,作为开发人员,我们需要比以往更好地准备我们的API,以提供可靠,高效的端点,应该能够毫不费力地浏览大量数据。
如果您已经进行了一段时间的后端或数据库体系结构,则可能已经完成了分页查询,如下所示:
对?
但是,如果您确实建立了这样的分页,很遗憾地说,您做错了。
你不同意我吗? 你 并不 需要 到 。 Slack, Shopify和Mixmax使用我们今天将要讨论的相同概念对API进行分页。
我想请您说说一个单一的后端开发人员,该人员从来没有为了分页目的而需要处理OFFSET和LIMIT。 对于MVP和低数据列表中的分页,它“有效”。
但是,当您想从头开始构建可靠而有效的系统时,也可以直接进行。
今天,我们将讨论(错误地)广泛使用的实现所存在的问题以及如何实现高效的分页。
正如我们在上几段中简要探讨的那样,OFFSET和LIMIT非常适合于数据使用量很少甚至没有的项目。
当数据库开始收集的数据量超出服务器可以存储在内存中的数据量时,仍然会出现问题,而您仍然需要对它们全部进行性能分页。
为此,每次您请求分页时,数据库都需要执行低效的全表扫描 (插入和删除可能同时发生,我们不希望数据过时!)。
什么是全表扫描? 全表扫描(又称顺序扫描)是在数据库中进行的扫描,其中顺序读取表中的每一行,然后检查遇到的列是否符合条件。 由于从磁盘进行大量的I / O读取(包括多次搜寻)以及昂贵的磁盘到内存传输,这种类型的扫描被认为是最慢的。
这意味着,如果您有100.000.000用户,而您要求的偏移量为50.000.000,则它将需要获取所有这些记录(甚至不需要!),并将它们存储在内存中,只有在获得之后, LIMIT中指定了20个结果。
因此,要在网站上显示这样的分页:
50.000至50.020之100.000
它首先需要获取50.000行。 看看这效率低下吗?
如果您不相信我,请看一下我创建的这个小提琴 。 在左侧面板中,您有一个基本架构,该架构将为我们的测试插入100.000行,而在右侧,则是有问题的查询和我们的解决方案。 只需单击顶部的“运行 ”,然后比较每个执行时间。 #1(问题查询)至少需要30秒钟的时间才能运行。
随着更多的数据,情况变得更加糟糕。 看看我的1000万行概念证明 。
现在,这应该使您对幕后发生的事情有所了解。 如果您喜欢阅读的内容,请在此处订阅以获取更多类似内容。
TLDR; 偏移量越高,查询将花费的时间越长。
这是您应该使用的:
这是基于游标的分页 。
您应该存储最后接收到的主键(通常是一个ID)和LIMIT,而不是在本地存储当前的OFFSET和LIMIT并随每个请求传递它,因此查询最终可能与此类似。
为什么? 因为通过显式传递最新的读取行,您可以根据有效的索引键告诉数据库确切从哪里开始搜索,而不必考虑该范围之外的任何行。
以下面的比较为例:
针对我们的优化版本:
接收到的记录完全相同,但是第一个查询花费了12.80秒,第二个查询花费了0.01秒。 你能体会到差异吗?
为了使Cursor Pagination无缝地工作,您将需要具有一个唯一的顺序列(或多个列),例如唯一的整数ID或时间戳记字段,在某些特定情况下,这可能会破坏交易。
与往常一样,我的建议是始终考虑每种表体系结构的优缺点以及在每种表体系结构中需要执行哪种查询。
如果您需要在查询中处理大量相关数据,Rick James的“ 列表”文章可能会为您提供更深入的指导。 如果我们遇到的问题与没有主键有关,例如,如果我们有多对多关系表,则在这些情况下始终可以使用传统的OFFSET / LIMIT方法,但这将重新引入潜在的较慢查询。 因此,我建议在要分页的表中使用自动递增的主键,即使只是出于分页的目的。
这样做的主要要点是始终检查查询的性能是1k行还是1M。 可伸缩性至关重要,如果从一开始就正确实施,肯定会避免将来出现很多麻烦。
哦。 并且,请不要忘记学习索引 。 并解释查询 。
如果您喜欢这篇文章,请 在此处订阅 以获取更多类似内容。
先前发布在 https://ivopereira.net/content/efficiency-pagination-dont-use-offset-limit
翻译自: https://hackernoon.com/please-dont-use-offset-and-limit-for-your-pagination-8ux3u4y