这是一个普遍的问题,适用于MySQL,Oracle DB或其他任何可能存在的问题。
我知道MySQL有LIMIT偏移,大小;对于Oracle,有“ROW_NUMBER”或类似的东西。
但是当这种“分页”查询被背靠背调用时,数据库引擎是否实际上重新执行了整个“选择”,然后每次检索不同的结果子集?或者它只对结果进行一次整体提取,将结果保存在内存中,然后根据偏移和大小为后续查询提供结果的子集?
如果它每次都进行完全获取,那么效率似乎非常低。
如果它只进行一次完全获取,它必须以某种方式“存储”某个地方的查询,以便下次查询进入时,它知道它已经获取了所有数据,只需要从中提取下一页它。 在这种情况下,数据库引擎将如何处理多个线程?两个线程执行相同的查询?
我很困惑:(
答案 0 :(得分:4)
我不同意@Bill Karwin。首先,不要事先做出假设是否快速或慢速而不进行测量,并提前使代码复杂化,一次下载12页并缓存它们,因为“在我看来它会更快”。
YAGNI principle - 程序员在认为必要之前不应添加功能
以最简单的方式(一页的普通分页),测量它在生产中的工作方式,如果它很慢,然后尝试不同的方法,如果速度令人满意,请保持原样。
从我自己的实践 - 一个从包含大约80,000条记录的表中检索数据的应用程序,主表与4-5个额外的查找表连接,整个查询被分页,每页大约25-30条记录,大约2500总共-3000页。数据库是Oracle 12c,有几列索引,查询是由Hibernate生成的。
服务器端生产系统的测量表明,检索一页的平均时间(中位数 - 50%百分位数)约为300毫秒。 95%百分位数小于800毫秒 - 这意味着当我们从服务器向用户添加传输时间并且渲染时间约为0.5-1秒时,95%的检索单个页面的请求少于800毫秒,总时间少于2秒。这就足够了,用户很高兴。
还有一些理论 - 请参阅此答案以了解Pagination pattern
的目的是什么答案 1 :(得分:1)
是的,当您使用不同的OFFSET运行查询时,将再次执行该查询。
是的,效率低下。如果您需要对大型结果集进行分页,请不要这样做。
我建议执行一次查询,使用大限制 - 足够10或12页。然后将结果保存在缓存中。当用户想要浏览多个页面时,您的应用程序可以获取您在缓存中保存的10-12页并显示用户想要查看的页面。这通常比为每个页面运行SQL查询快得多。
如果像大多数用户一样,您的用户只读取几页然后更改其查询,那么这种方法很有效。
重新评论:
通过缓存我的意思是像Memcached或Redis。高速,内存中的键/值存储。
MySQL视图不存储任何内容,它们更像是为您运行预定义查询的宏。
Oracle支持物化视图,因此可能效果更好,但查询视图会产生解释SQL查询的开销。
更简单的内存缓存应该更快。