分页来自数据库的数据时,您需要知道将有多少页面呈现页面跳转控件.
目前我通过运行查询两次,一次包装count()
以确定总结果,第二次应用限制以获取当前页面所需的结果.
这似乎效率低下.有没有更好的方法来确定在LIMIT
应用之前会返回多少结果?
我正在使用PHP和Postgres.
自2008年以来情况发生了变化.您可以使用窗口函数在一个查询中获取完整计数和有限结果.(2009年推出PostgreSQL 8.4).
SELECT foo
, count(*) OVER() AS full_count
FROM bar
WHERE
ORDER BY
LIMIT
OFFSET ;
请注意,这可能比没有总数更昂贵.必须对所有行进行计数,并且仅使用匹配索引中的顶行可能的快捷方式可能不再有用.
与小表或full_count
<= OFFSET
+ 无关LIMIT
.事情要大得多full_count
.
OFFSET
极端情况:当至少与基本查询中的行数一样大时,不返回任何行.所以你也没有full_count
.可能的选择:
使用LIMIT/OFFSET运行查询,并获取总行数
考虑一系列事件:
SELECT
子句(和WHERE
条件,但不是这里)过滤基表中的限定行.
(JOIN
和聚合函数会在这里.)
考虑所有符合条件的行(取决于GROUP BY
函数的子句和框架规范),应用窗口函数.简单SELECT
基于所有行.
OVER
(count(*) OVER()
或者ORDER BY
会去这里.)
DISTINCT
/ DISTINCT ON
根据建立的顺序应用,以选择要返回的行.
LIMIT
/ OFFSET
表中的行数越来越多,效率越来越低.如果您需要更好的性能,请考虑其他方法
在大表上使用OFFSET优化查询
有完全不同的方法来获得受影响的行数(不完整的计数之前LIMIT
与OFFSET
被应用).Postgres具有内部簿记,受上一个SQL命令影响的行数.有些客户端可以访问该信息或自行计数行(如psql).
例如,您可以在执行SQL命令后立即检索plpgsql中受影响的行数:
GET DIAGNOSTICS integer_var = ROW_COUNT;
手册中的详细信息.
或者你可以OFFSET
在PHP中使用.或其他客户端中的类似功能.
有关:
计算PostgreSQL中受批处理查询影响的行数
正如我在博客中描述的那样,MySQL有一个名为SQL_CALC_FOUND_ROWS的功能.这消除了两次执行查询的需要,但它仍然需要完整地进行查询,即使limit子句允许它提前停止.
据我所知,PostgreSQL没有类似的功能.在进行分页时要注意的一件事(使用LIMIT最常见的事情是恕我直言):执行"OFFSET 1000 LIMIT 10"意味着数据库必须至少获取1010行,即使它只给你10分.更高效的方法是记住前一行(在本例中为1000)排序的行的值,并重写查询,如下所示:"... WHERE order_row> value_of_1000_th LIMIT 10".优点是"order_row"很可能被索引(如果没有,你就会出问题).缺点是如果在页面视图之间添加新元素,这可能会有点不同步(但是再一次,它可能无法被访问者观察到并且可以获得很大的性能提升).