数据库中的结果分页如何工作?

shi*_*shu 3 mysql database oracle paging pagination

这是一个普遍的问题,适用于MySQL,Oracle DB或其他可能存在的问题。

我知道对于MySQL有LIMIT offset,size; 对于Oracle,有“ ROW_NUMBER”或类似名称。

但是,当这样的“分页”查询被背靠背调用时,数据库引擎是否真的重新进行整个“选择”,然后每次都检索不同的结果子集?还是只对结果进行一次整体提取,是否将结果保存在内存中,然后再根据偏移量和大小将结果的子集提供给后续查询?

如果它每次都执行完整提取,那么它似乎效率很低。

如果它仅执行一次全读取,则它必须以某种方式“存储”查询,以便下次查询进入时,它知道它已经获取了所有数据,只需要从中提取下一页即可。在这种情况下,数据库引擎将如何处理多个线程?两个线程执行相同的查询?

我很迷茫 :(

Bil*_*win 8

是的,当您使用不同的 OFFSET 运行查询时,它会再次执行。

是的,这是低效的。如果您需要对大型结果集进行分页,请不要这样做。

我建议查询一次,使用大 LIMIT — 足够 10 或 12 页。然后将结果保存在缓存中。当用户想要浏览多个页面时,您的应用程序可以获取您保存在缓存中的 10-12 个页面并显示用户想要查看的页面。这通常比为每个页面运行 SQL 查询快得多。

如果像大多数用户一样,您的用户只阅读了几页,然后更改了他们的查询,那么这种方法会很有效。


回复您的评论:

我所说的缓存指的是 Memcached 或 Redis 之类的东西。高速内存键/值存储。

MySQL 视图不存储任何内容,它们更像是一个为您运行预定义查询的宏。

Oracle 支持物化视图,因此它可能工作得更好,但查询视图会产生解释 SQL 查询的开销。

更简单的内存缓存应该更快。


kro*_*lko 5

我不同意@Bill Karwin。首先,不要事先假设某些东西是快速还是慢而不进行测量,而要提前使代码复杂化以一次下载12页并缓存它们,因为“在我看来,它会更快”。

YAGNI原则 -程序员在认为必要之前不应添加功能。
以最简单的方式(一页的普通分页)进行操作,测量其在生产中的工作方式,如果速度缓慢,则尝试另一种方法,如果速度令人满意,则保持原样。


从我自己的实践来看-一个应用程序从包含约80,000条记录的表中检索数据,主表与4-5个附加查找表连接在一起,对整个查询进行分页,每页约25-30条记录,约2500-3000页总共。数据库是Oracle 12c,在几列上都有索引,查询是由Hibernate生成的。在服务器端的生产系统上进行的测量表明,检索一页的平均时间(中位数-50%百分位数)约为300毫秒。95%的百分位数小于800毫秒-这意味着,当我们添加从服务器到用户的传输时间和大约0.5-1秒的呈现时间时,检索单个页面的95%的请求小于800毫秒。总时间少于2秒。足够了,用户很高兴。


还有一些理论-请参阅此答案以了解分页模式的目的是什么

  • 我同意在实施变通方法之前应该首先进行测量以确保存在真正的性能问题。我假设性能问题是给定的。 (2认同)