PostgreSQL分页以及行号索引

时间:2018-05-24 14:42:28

标签: oracle postgresql database-migration

好的,我正致力于将 oracle DB 的查询移植到postgres。我的查询需要给我编号记录,以及分页。

考虑以下oracle代码:

select * from (
    select RS.*, ROWNUM as RN from ( 
        select * from STUDENTS order by GRADES
    ) RS where ROWNUM <= (#{startIndex} + #{pageSize}) 
) where RN > #{startIndex}

请注意,ROWNUM有两种用途:

  1. 为查询结果中的每一行提供行号。
  2. 分页。
  3. 我需要将此类查询移植到postgres

    我知道如何使用LIMITOFFSET命令对分页进行分页,但我无法提供全局行号(查询结果中的每一行都会获得唯一的行号)。

    另一方面,我能够找到可以为我提供全局行号的ROW_NUMBER()命令,但由于我的数据库中的元组数量非常大,因此不会因为分页而推荐。

    如何在postgres中编写类似的代码?

1 个答案:

答案 0 :(得分:1)

解决方案在PostgreSQL中看起来更简单:

SELECT *,
       row_number() OVER (ORDER BY grades) AS rn
FROM students
ORDER BY grades
OFFSET $1 LIMIT $2;

如果grades上有索引并且偏移量不是太高,那么该查询是有效的:

EXPLAIN (ANALYZE)
SELECT *,
       row_number() OVER (ORDER BY grades) AS rn
FROM students
ORDER BY grades
OFFSET 10 LIMIT 20;

                             QUERY PLAN                                                                   
-------------------------------------------------------------------
 Limit  (cost=1.01..2.49 rows=20 width=20)
        (actual time=0.204..0.365 rows=20 loops=1)
   ->  WindowAgg  (cost=0.28..74.25 rows=1000 width=20)
                  (actual time=0.109..0.334 rows=30 loops=1)
         ->  Index Scan using students_grades_idx on students
                        (cost=0.28..59.25 rows=1000 width=12)
                        (actual time=0.085..0.204 rows=30 loops=1)
 Planning time: 0.515 ms
 Execution time: 0.627 ms
(5 rows)

观察计划中的actual值。

OFFSET的分页总是效率低,偏差很大;考虑keyset pagination