在分析来自数据库的数据时,您需要知道将有多少页面呈现页面跳转控件。
目前,我通过运行查询两次,一次包裹在count()
中确定总结果,第二次应用限制来获取当前页面所需的结果。< / p>
这似乎效率低下。有没有更好的方法来确定在应用LIMIT
之前会返回多少结果?
我正在使用PHP和Postgres。
答案 0 :(得分:117)
自2008年以来情况发生了变化。您可以使用window function在一个查询中获取完整计数和有限结果。 (引入PostgreSQL 8.4 in 2009)。
SELECT foo
, count(*) OVER() AS full_count
FROM bar
WHERE <some condition>
ORDER BY <some col>
LIMIT <pagesize>
OFFSET <offset>
请注意,与没有总计数相比,这可能要贵得多。必须对所有行进行计数,并且仅使用匹配索引中的顶行可能的快捷方式可能不再有用
小表或full_count
&lt; = OFFSET
+ LIMIT
无关紧要。事情要大得多full_count
。
转角案例 :当OFFSET
至少与基本查询中的行数一样大时, 没有行<退回/ em> 。所以你也没有full_count
。可能的替代方案:
考虑事件序列:
WHERE
子句(和JOIN
条件,但不在此处)从基表中过滤限定行。
(GROUP BY
和聚合函数将在这里。)
考虑所有符合条件的行(取决于OVER
子句和函数的帧规范),应用窗口函数。简单的count(*) OVER()
基于所有行。
ORDER BY
(DISTINCT
或DISTINCT ON
会在这里。)
LIMIT
/ OFFSET
根据已建立的顺序应用,以选择要返回的行。
LIMIT
/ OFFSET
的效率越来越低。如果您需要更好的性能,请考虑其他方法:
有一些完全不同的方法来获取受影响的行数( 不 在应用OFFSET
&amp; LIMIT
之前的完整计数) 。 Postgres具有内部簿记,受上一个SQL命令影响的行数。有些客户端可以访问该信息或自行计数行(如psql)。
例如,您可以在执行SQL命令后立即检索 plpgsql 中受影响的行数:
GET DIAGNOSTICS integer_var = ROW_COUNT;
或者您可以使用pg_num_rows
in PHP。或其他客户的类似功能。
相关:
答案 1 :(得分:5)
正如我所描述的on my blog,MySQL有一个名为SQL_CALC_FOUND_ROWS的功能。这样就无需进行两次查询,但仍然需要完整地进行查询,即使限制条款允许它提前停止。
据我所知,PostgreSQL没有类似的功能。在进行分页时要注意的一件事(使用LIMIT最常见的事情是恕我直言):执行“OFFSET 1000 LIMIT 10”意味着数据库必须至少提取 1010行如果它只给你10.一个更高效的方法是记住你为前一行(在这种情况下为1000)排序的行的值,并重写这样的查询:“... WHERE order_row&gt ; value_of_1000_th LIMIT 10“。优点是“order_row”很可能被索引(如果没有,你就会出问题)。缺点是如果在页面视图之间添加新元素,这可能会有点不同步(但话说,访问者可能无法观察到它,并且可能会带来巨大的性能提升)。
答案 2 :(得分:1)
您可以通过不每次运行COUNT()查询来减轻性能损失。缓存页数,比如再次运行查询前5分钟。除非你看到大量的INSERT,否则它应该可以正常工作。
答案 3 :(得分:0)
由于Postgres已经执行了一定数量的缓存,因此这种方法并不像看起来那么低效。绝对不会使执行时间加倍。我们的数据库层内置了计时器,所以我看到了证据。
答案 4 :(得分:-1)
看到你需要知道为了分页的目的,我建议运行一次完整的查询,将数据作为服务器端缓存写入磁盘,然后通过分页机制提供。
如果您正在运行COUNT查询以决定是否向用户提供数据(即,如果有&gt; X记录,请回复错误),您需要坚持使用COUNT方法