出于分页的目的,我需要运行一个包含LIMITOFFSET子句的查询.但是,我还需要一个计数,该查询在没有LIMITOFFSET子句的情况下将返回多少行.

我想 run :

SELECT * FROM table WHERE /* whatever */ ORDER BY col1 LIMIT ? OFFSET ?

以及:

SELECT COUNT(*) FROM table WHERE /* whatever */

同时有没有办法做到这一点,特别是有没有办法让Postgres对其进行优化,使其比单独运行两者更快?

推荐答案

Yes.,具有简单的窗口功能:

SELECT *, count(*) OVER() AS full_count
FROM   tbl
WHERE  /* whatever */
ORDER  BY col1
OFFSET ?
LIMIT  ?

请注意,成本将大大高于没有总数的情况,但通常仍比两个单独的查询便宜.无论哪种方式,Postgres实际上都必须达到count all rows,这就需要根据符合条件的行的总数来确定成本.细节:

Howeveras Dani pointed out,当OFFSET至少等于从基本查询返回的行数时,不会返回任何行.所以我们也没有得到full_count.

如果这是不可接受的,workaround to always return the full count可能会配备CTE和OUTER JOIN:

WITH cte AS (
   SELECT *
   FROM   tbl
   WHERE  /* whatever */
   )
SELECT *
FROM  (
   TABLE  cte
   ORDER  BY col1
   LIMIT  ?
   OFFSET ?
   ) sub
RIGHT  JOIN (SELECT count(*) FROM cte) c(full_count) ON true;

如果OFFSET太大,将得到一行带有full_count的空值.否则,它会像第一个查询一样附加到每一行.

如果一个包含所有空值的行是一个可能的有效结果,则必须选中offset >= full_count以消除空行来源的歧义.

这仍然只执行一次基本查询.但它会给查询增加更多开销,并且只有在这比重复基本查询的次数少的情况下,才会支付费用.

如果支持最终排序顺序的索引可用,那么将ORDER BY包含在CTE中(冗余)可能是值得的.

Sql相关问答推荐

如何用3个(半)固定位置建模团队,并有效地搜索相同/不同的团队?

基于多个字段删除Access中的重复记录,同时保留最低优先级

在请求结束之前,PostgreSQL不会考虑使用中的删除

连接特定行号

使用占位符向SQL INSERT查询添加 case

为什么两个不同的窗口函数给出不同的排序结果?

返回UPSERT中的旧行值

Oracle分层查询-两条路径在末尾合并为一条

如何用QuestDB生成蜡烛图?

PostgreSQL中递归CTE查询的故障过滤

在特定条件下使用 LAG,确定要采用什么 LAG 值?

SQL 查找 varchar 类型列及其值中多次出现的子字符串

删除重复记录但保留最新的SQL查询

Postgres更新增量之间的差异

try 将多行折叠为单个结果

如何在 ClickHouse SQL 中使用 CTE 将邻居语句中的数字作为偏移量传递?

Select 字段,除非另一个字段包含重复项

根据开始/结束标记将 GROUP_ID 分配给行

CURRENT_ROW 窗口框架上的 SQL 滞后

如何优化sql请求?