不需要担心数据库性能优化问题的日子已经一去不复返了。随着时代的进步,随着雄心勃勃的企业想要成为下一个Facebook,随着为机器学习预测收集尽可能多的数据的想法的出现,我们作为开发人员不断地磨练我们的API,以便他们提供可靠和高效的端点轻松浏览海量数据。如果你做过后台开发或者数据库架构,你很可能是这样进行分页的:如果你真的这样进行分页,那么很抱歉,你做错了。你不这么认为吗?没关系。Slack、Shopify和Mixmax等公司都在按照我们今天要讨论的方式进行分页。我认为您很难找到不使用OFFSET和LIMIT进行数据库分页的人。对于简单的小应用和数据量不大的场景,这种方式还是可以“应付”的。如果您想从头开始构建一个可靠且高效的系统,请从一开始就把它做好。今天我们将讨论目前广泛使用的分页方式存在的问题,以及如何实现高性能的分页。1、OFFSET和LIMIT有什么问题?上一段提到,OFFSET和LIMIT对于数据量小的项目是没有问题的。但是,当数据库中的数据量超过了服务器内存的容量时,问题就出现了,所有的数据都需要进行分页。为了实现分页,数据库每次收到分页请求都需要做一次低效的全表扫描。什么是全表扫描?全表扫描(也称为顺序扫描)是逐行扫描数据库,依次读取表中的每一行,然后检查每一列是否满足查询条件。由于需要大量磁盘I/O以及从磁盘到内存的传输开销,此扫描是已知的最慢扫描。也就是说,如果你有1亿用户,OFFSET是5000万,那么它需要把那些记录(包括那么多根本不需要的数据)全部取出来,放到内存中,然后取出指定的20条结果通过限制。也就是说,要获取一页的数据:10万行中的第50000行到第50020行需要先获取50000行。这是多么低效?不信你看看这个例子:https://www.db-fiddle.com/f/3...左边的SchemaSQL会插入10万行数据,右边有性能不佳的查询和更好的解决方案。只需单击顶部的运行即可比较它们的执行时间。第一个查询的运行时间至少比第二个查询长30倍。数据越多,情况就越糟。查看我关于10万行数据的PoC。https://github.com/IvoPereira...现在你应该知道幕后发生了什么:OFFSET越高,查询时间越长。2.备选方案你应该这样做:这是一种基于指针的分页。您想将最后收到的主键(通常是一个ID)和LIMIT保存在本地,而不是OFFSET和LIMIT,因此每次查询可能与此类似。为什么?因为通过显式地告诉数据库最新的行,数据库确切地知道从哪里开始搜索(基于有效的索引),而不管目标范围之外的记录。比较此查询:与优化版本:返回相同的结果,第一个查询耗时12.80秒,而第二个仅耗时0.01秒。要使用这种基于游标的分页,您需要有一个唯一的序列字段(或多个),例如唯一的整数ID或时间戳,但在某些特定情况下这可能是不可能的。我的建议是无论如何都要考虑每种解决方案的优缺点,以及您需要执行什么样的查询。如果您需要基于大量数据进行查询,RickJames的文章提供了更深入的指导。http://mysql.rjweb.org/doc.ph...如果我们的表没有主键,比如多对多关系的表,那就用传统的OFFSET/LIMIT方法,但是它是潜在的慢查询问题。我建议在需要分页的表中使用自动递增的主键,即使只是为了分页。来源:今日头条/i6860655404431442444
