使用SQL查询时,最有效的分页方式是什么?

时间:2020-03-05 18:50:17  来源:igfitidea点击:

我正在尝试对要在网页上使用的SQL查询的结果进行分页。语言和数据库后端是PHP和SQLite。

我正在使用的代码的工作原理如下(页码从0开始)

http://example.com/table?page=0

page = request(page)
per = 10 // results per page
offset = page * per

// take one extra record so we know if a next link is needed
resultset = query(select columns from table where conditions limit offset, per + 1)

if(page > 0) show a previous link
if(count(resultset) > per) show a next link

unset(resultset[per])

display results

是否有比这更有效的分页方法?

使用当前方法可以看到的一个问题是,在开始显示结果之前,必须将所有10个(或者许多)结果存储在内存中。我这样做是因为PDO不保证行数可用。

发出COUNT(*)查询以了解存在多少行,然后将结果流式传输到浏览器是否更有效?

这是"它取决于表的大小,以及count(*)查询是否需要在数据库后端进行全表扫描","做一些性能分析"这类问题之一吗?

解决方案

回答

我建议先算一下。一个count(主键)是一个非常有效的查询。

回答

我怀疑用户等待后端返回十行是否会成为问题。 (我们可以通过指定图像尺寸来弥补它们的不足,让网络服务器在可能的情况下协商压缩数据的传输,等等。)

我认为最初做一个count(*)对我们来说不是很有用。

如果我们需要一些复杂的编码,请执行以下操作:当用户查看第x页时,请使用类似ajax的魔术来预加载第x + 1页,以改善用户体验。

有关分页的一般说明:
如果在用户浏览页面时数据发生了变化,那么如果解决方案要求非常高的一致性,则可能是一个问题。我已经在其他地方写了关于此的注释。

回答

我选择使用COUNT(*)两个查询方法,因为它允许我直接创建到最后一页的链接,而其他方法则不允许。首先执行计数也使我能够流式传输结果,因此应该在内存较少的情况下处理大量记录时效果很好。

页面之间的一致性对我来说不是问题。谢谢帮助。

回答

在几种情况下,我有一个相当复杂的查询(9-12表联接),返回成千上万的行,需要分页。显然,要很好地分页,我们需要知道结果的总大小。对于MySQL数据库,在SELECT中使用SQL_CALC_FOUND_ROWS指令可以轻松实现这一目标,尽管尚不能确定这样做是否会更有效。

但是,由于我们使用的是SQLite,所以我建议坚持使用2查询方法。这是此事的一个非常简洁的线索。