Tim*_*Tim 56 sql postgresql pagination count limit
出于分页目的,我需要使用LIMIT
和OFFSET
子句运行查询.但是我还需要计算没有LIMIT
和OFFSET
子句的查询返回的行数.
我想跑:
SELECT * FROM table WHERE /* whatever */ ORDER BY col1 LIMIT ? OFFSET ?
Run Code Online (Sandbox Code Playgroud)
和:
SELECT COUNT(*) FROM table WHERE /* whatever */
Run Code Online (Sandbox Code Playgroud)
同时.有没有办法做到这一点,特别是让Postgres优化它的方式,这样它比单独运行更快?
Erw*_*ter 106
是.具有简单的窗口功能:
SELECT *, count(*) OVER() AS full_count
FROM tbl
WHERE /* whatever */
ORDER BY col1
LIMIT ?
OFFSET ?
Run Code Online (Sandbox Code Playgroud)
请注意,成本将远高于没有总数的成本,但仍然比两个单独的查询便宜.在任何一种情况下,Postgres都必须实际计算所有行,这会产生一定的成本,具体取决于合格行的总数.细节:
但是,正如Dani指出的那样,当OFFSET
至少与从基本查询返回的行数一样大时,不会返回任何行.所以我们也没有得到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;
Run Code Online (Sandbox Code Playgroud)
你得到一行NULL值,full_count
附加的if OFFSET
太大了.或者它像第一个查询中一样附加到每一行.
如果具有所有NULL值的行是可能的有效结果,则必须检查offset >= full_count
以消除空行的原点的歧义.
这仍然只执行一次基本查询.但它增加了查询的开销,只有在重复计数的基本查询时才会付费.
如果支持最终排序顺序的索引可用,则可能需要ORDER BY
在CTE中包含(冗余).
tre*_*con 18
虽然Erwin Brandstetter的答案非常有效,但它返回每行的总行数,如下所示:
col1 - col2 - col3 - total
--------------------------
aaaa - aaaa - aaaa - count
bbbb - bbbb - bbbb - count
cccc - cccc - cccc - count
Run Code Online (Sandbox Code Playgroud)
您可能需要考虑使用仅返回一次总数的方法,如下所示:
total - rows
------------
count - [{col1: 'aaaa'},{col2: 'aaaa'},{col3: 'aaaa'}
{col1: 'bbbb'},{col2: 'bbbb'},{col3: 'bbbb'}
{col1: 'cccc'},{col2: 'cccc'},{col3: 'cccc'}]
Run Code Online (Sandbox Code Playgroud)
SQL查询:
SELECT
(SELECT COUNT(*)
FROM table
WHERE /* sth */
) as count,
(SELECT json_agg(t.*) FROM (
SELECT * FROM table
WHERE /* sth */
ORDER BY col1
OFFSET ?
LIMIT ?
) AS t) AS rows
Run Code Online (Sandbox Code Playgroud)
编辑:这个答案在检索未过滤的表时有效。我会让它以防万一它可以帮助某人,但它可能无法完全回答最初的问题。
如果您需要准确的值, Erwin Brandstetter的答案是完美的。然而,在大表上,您通常只需要一个相当好的近似值。Postgres为您提供了这一点,并且速度会快得多,因为它不需要评估每一行:
SELECT *
FROM (
SELECT *
FROM tbl
WHERE /* something */
ORDER BY /* something */
OFFSET ?
LIMIT ?
) data
RIGHT JOIN (SELECT reltuples FROM pg_class WHERE relname = 'tbl') pg_count(total_count) ON true;
Run Code Online (Sandbox Code Playgroud)
我实际上不太确定将其外部化RIGHT JOIN
或像在标准查询中那样具有它是否有优势。它值得一些测试。
SELECT t.*, pgc.reltuples AS total_count
FROM tbl as t
RIGHT JOIN pg_class pgc ON pgc.relname = 'tbl'
WHERE /* something */
ORDER BY /* something */
OFFSET ?
LIMIT ?
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
31226 次 |
最近记录: |