当前位置: 首页 > 科技观察

为什么不应该在分页中使用offset和limit

时间:2023-03-17 19:56:11 科技观察

不需要担心数据库性能优化的日子已经一去不复返了。随着时代的进步和每个新企业家都想建立下一个Facebook,再加上收集每个可能的数据点以提供更好的机器学习预测的心态,作为开发人员,我们需要比以往更好地准备我们的API,以提供可靠且应该能够导航大量数据的高效端点。如果你做过一段时间的后台或数据库架构,你可能做过分页查询,就像这样。正确的?但是,如果您确实创建了这样的分页,我很抱歉地说,您做错了。你不同意我的看法?你不必。Slack、Shopify和Mixmax都在使用我们今天将介绍的概念对它们的API进行分页。我希望您指定一个后端开发人员,他没有处理过分页OFFSET和LIMIT,对于低数据列表中的MVP和分页,它“有效”。今天我们将讨论广泛使用的(错误的)实现有什么问题,以及如何实现高性能分页。OFFSET和LIMIT有什么问题?正如我们在前几段中简要探讨的那样,OFFSET和LIMIT非常适合数据使用量很少或没有的项目。当您的数据库开始收集比服务器可以存储在内存中的数据更多的数据时,就会出现问题,并且您仍然需要以高性能对这些数据进行分页。为此,数据库需要在每次请求分页时执行低效的全表扫描(在此期间可能会发生插入和删除,我们不希望数据过时!)。什么是全表扫描?全表扫描(akasequentialscan)是指在数据库中进行扫描,依次读取表中的每条记录,然后检查遇到的列的条件是否有效。由于从磁盘读取大量I/O,包括多次寻道和昂贵的磁盘到内存传输,这种类型的扫描被认为是最慢的。这意味着如果您有100.000.000个用户,并且您要求OFFSET为50.000.000,它将需要获取所有这些记录(甚至不是!),将它们放入内存中,然后才会获得20个结果在LIMIT中指定。所以要在网站上显示这样的分页:50.000to50.020of100.000首先你需要获取50.000行,看看这样效率低吗?你应该使用什么这是你应该使用的:这是基于游标的分页。查询可以像这样结束,而不是在本地存储当前偏移量和限制并将其与每个请求一起传递。为什么?因为通过显式传递最近读取的行,您可以告诉数据库根据有效索引键从何处开始搜索,而无需考虑该范围之外的任何行。以下面的对比为例:针对我们的优化版本:收到完全相同的记录,但第一次查询耗时12.80秒,第二次耗时0.01秒。你能感觉到不同吗?注释要使游标分页无缝工作,您需要有一个唯一的、有序的列(或多个列),例如唯一的整数ID,在某些特定情况下,这可能会成为问题。一如既往,我的建议是始终考虑每个表模式的优缺点,以及您需要对每个表执行哪种查询。如果您需要在查询中处理大量相关数据,RickJames的“列表文章”可能会给您更深入的指导。如果手头的问题与没有主键有关,比如说我们有一个多对多的关系表,传统的OFFSET/LIMIT方法总是可以在这些情况下使用,但是这将重新引入可能更慢的查询。因此,我建议在要分页的表中使用自动递增的主键,即使只是为了分页目的。总结一下,主要的启发应该是无论你的查询使用1k行还是1M行,你都应该经常检查你的查询性能。可扩展性非常重要,如果从一开始就正确实施,肯定会避免许多未来的麻烦。哦。另外,不要忘记了解索引和解释查询。如果您正在寻找如何在ElasticSearch上实现游标分页,请随时查看文章ElasticSearch--这就是您应该如何对结果进行分页。ElasticSearch-这是您应该如何对结果进行分页:https://medium.com/@tmateus/elasticsearch-this-is-how-you-should-paginate-your-results-5d1c71bfe060