在应用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>
请注意,这可能比没有总数要昂贵得多。 所有的行都必须被计数,并且从匹配的索引只取最上面的行的快捷方式是不可能的。
与小桌子无关,与大桌子有关系。
考虑事件的顺序 :
-
WHERE
子句(和JOIN
条件,但不在此处)过滤来自基表的合格行。(
GROUP BY
和聚合函数会在这里。) -
考虑到所有符合条件的行(取决于函数的
OVER
子句和框架规范),将应用窗口函数。 简单count(*) OVER()
基于所有行。 -
ORDER BY
(
DISTINCT
或DISTINCT ON
会在这里。) -
根据build立的顺序应用
LIMIT
/OFFSET
select要返回的行。
请注意, 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层有定时器,所以我看到了证据。