在应用LIMIT之前获取结果数量的最佳方法

当分页来自数据库的数据时,您需要知道将有多less页面来呈现页面跳转控件。

目前我通过运行查询两次,一旦包裹在一个count()来确定总的结果,第二次应用一个限制,以获取我需要的当前页面的结果。

这似乎效率低下。 有没有更好的方法来确定LIMIT应用之前会有多less结果返回?

我正在使用PHP和Postgres。

纯SQL

事情自2008年以来发生了变化。您可以使用窗口函数来获取完整的计数和有限的结果在一个查询中。 ( 2009年用PostgreSQL 8.4引入)。

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

请注意,这可能比没有总数要昂贵得多。 所有的行都必须被计数,并且从匹配的索引只取最上面的行的快捷方式是不可能的。
与小桌子无关,与大桌子有关系。

考虑事件顺序

  1. WHERE子句(和JOIN条件,但不在此处)过滤来自基表的合格行。

    GROUP BY和聚合函数会在这里。)

  2. 考虑到所有符合条件的行(取决于函数的OVER子句和框架规范),将应用窗口函数。 简单count(*) OVER()基于所有行。

  3. ORDER BY

    DISTINCTDISTINCT ON会在这里。)

  4. 根据build立的顺序应用LIMIT / OFFSETselect要返回的行。

请注意, LIMIT / OFFSET在表中日益增多的行数变得越来越低效。 如果您需要更好的performance,请考虑其他方法:

  • 在大表上使用OFFSET优化查询

备择scheme

也有完全不同的方法。 Postgres有内部簿记在最后的SQL命令影响了多less行。 有些客户端可以自己访问这些信息或者统计行数(如psql)。

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

 GET DIAGNOSTICS integer_var = ROW_COUNT; 

手册中的细节。

或者你可以在PHP中使用pg_num_rows

  • 计算在PostgreSQL中受批量查询影响的行数

代码示例:

  • 计算在PostgreSQL中受批量查询影响的行数

正如我在我的博客中所描述的,MySQL有一个名为SQL_CALC_FOUND_ROWS的function。 这消除了查询两次的需要,但是它仍然需要完整地查询查询,即使限制条款允许它提前停止。

据我所知,PostgreSQL没有类似的function。 在做分页时要注意的一件事(使用LIMIT的最常见的事情是:恕我直言):做一个“OFFSET 1000 LIMIT 10”意味着数据库至less要获取1010行,即使它只给出了10行。更高效的方法是记住前一行(本例中为第1000行)的sorting行的值,并重写如下查询:“… WHERE order_row> value_of_1000_th LIMIT 10”。 优点是,“order_row”最有可能是索引(如果不是,你遇到了问题)。 缺点是如果在页面视图之间添加新的元素,这可能会有一点不同步(但是再次,它可能不被访问者观察到并且可以是大的性能增益)。

看到你需要知道的分页目的,我会build议运行一次完整的查询,将数据写入磁盘作为服务器端caching,然后通过您的分页机制喂养。

如果您正在运行COUNT查询来决定是否向用户提供数据(即,如果有> X个logging,则返回错误),则需要使用COUNT方法。

您可以通过不每次运行COUNT()查询来减轻性能损失。 在查询再次运行之前,caching5分钟的页数。 除非你看到大量的INSERT,这应该工作得很好。

由于Postgres已经做了一定数量的caching,所以这种方法并不像看起来那么低效。 这绝对不会使执行时间加倍。 我们在我们的DB层有定时器,所以我看到了证据。

Interesting Posts