当呼通过数据来自一个数据库,你需要知道有多少网页将有渲染页跳的控制。

目前我所做的,通过运行查询两次,一次在一个包裹 count() 确定总的结果,以及第二的时间用限制施加于回来的只是结果我需要对当前页。

这看起来效率低下。是否有更好的办法来确定有多少结果将已经返回之前 LIMIT 是适用?

我使用PHP和Postgres。

有帮助吗?

解决方案

纯SQL

事情已经改变,因为2008年。你可以使用 窗口的功能 得到充分计和有限的结果在一个查询。(引用 PostgreSQL8.4在2009年).

SELECT foo
     , count(*) OVER() AS full_count
FROM   bar
WHERE  <some condition>
ORDER  BY <some col>
LIMIT  <pagesize>
OFFSET <offset>

注意,这可能是相当昂贵的,比没有总计。所有行计算,以及一个可能的快捷服只是顶部的行匹配指数可能不是有助益的任何更多。
不论多小表或 full_count <= OFFSET + LIMIT.事项的一个更大的基本上 full_count.

角落的情况下:时 OFFSET 至少作为行的数量从基查询, 没有行 返回。所以你也没有得到任何 full_count.可能的选择:

请考虑 列事件:

  1. WHERE 条款(以及 JOIN 条件,但不是在这里)的过滤器符合资格的行从基table(s)。

    (GROUP BY 和总体功能会在这里.)

  2. 窗口的功能应用考虑到所有符合资格的行(这取决于 OVER 条款和框架规范的功能)。简单的 count(*) OVER() 基于所有行。

  3. ORDER BY

    (DISTINCTDISTINCT ON 会在这里.)

  4. LIMIT / OFFSET 应用基于成立以选择行返回。

LIMIT / OFFSET 变得越来越低效率的越来越多的行表中。考虑替代办法,如果你需要更好的业绩:

替代品,以获得最终计数

还有完全不同的方法得到最受影响的行( 全计数之前 OFFSET & LIMIT 被施加)。Postgres有内部簿记有多少行其影响的最后一SQL command.一些客户可以访问的信息或数行本身(似的原因).

例如,你可以检索的数受影响的行中 plpgsql 之后立即执行SQL命令有:

GET DIAGNOSTICS integer_var = ROW_COUNT;

详细的手册。

或者您可以使用 pg_num_rowsPHP.或类似的功能在其他客户。

相关:

其他提示

我在我的博客上描述 有一个名为 SQL_CALC_FOUND_ROWS 的功能。这样就无需进行两次查询,但仍然需要完整地进行查询,即使限制条款允许它提前停止。

据我所知,PostgreSQL没有类似的功能。做分页时要注意的一件事(使用LIMIT最常见的事情是恕我直言):做一个<!>“OFFSET 1000 LIMIT 10 <!>”;表示数据库必须至少提取 1010行,即使它只给你10个。更高效的方法是记住你为前一行排序的行的值(在这种情况下的第1000个)并重写这样的查询:<!> quot; ... WHERE order_row <!> gt; value_of_1000_th LIMIT 10 <!> quot;。优点是<!> quot; order_row <!> quot;最有可能被编入索引(如果没有,你就会出问题)。缺点是如果在页面视图之间添加新元素,这可能会有点不同步(但话说,访问者可能无法观察到它,并且可能会带来巨大的性能提升)。

您可以通过不每次运行COUNT()查询来减轻性能损失。缓存页数,比如再次运行查询前5分钟。除非你看到大量的INSERT,否则它应该可以正常工作。

由于Postgres已经执行了一定数量的缓存,因此这种方法并不像看起来那么低效。绝对不会使执行时间加倍。我们的数据库层内置了计时器,所以我看到了证据。

看到你需要知道为了分页的目的,我建议运行一次完整的查询,将数据作为服务器端缓存写入磁盘,然后通过分页机制提供。

如果您正在运行COUNT查询以决定是否向用户提供数据(即,如果有<!> gt; X记录,请回复错误),您需要坚持使用COUNT方法。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top