使用主键列表在大型表上进行Oracle分页

时间:2017-09-29 08:11:28

标签: sql oracle paging

我正在使用Oracle 11.2,并且正在尝试在包含数百万行的表上编写分页查询。阅读其他文章我认为我找到了最好的方法,但它减慢了页码越高。

这是我的解决方案。首先,我获得该页面数据的主键值(ID)列表。然后,我获得与这些ID匹配的所有其他表数据。然而,这仍然运行缓慢。

SELECT *
FROM mytable
WHERE ID IN (
    SELECT ID
    FROM (
        SELECT ID, ROWNUM rnum
        FROM (
            SELECT ID
            FROM mytable
            ORDER BY ID
        ) results
        WHERE ROWNUM <= 1000010
    )
    WHERE rnum >= 1000001
 )

执行时间:30秒以上。

如果我单独执行内部查询并手动将id传递给外部查询,则速度要快得多:

SELECT ID
FROM (
    SELECT ID, ROWNUM rnum
    FROM (
        SELECT ID
        FROM mytable
        ORDER BY ID
    ) results
    WHERE ROWNUM <= 1000010
)
WHERE rnum >= 1000001

Execution Time: 0.2 seconds.

Results: 
2134696,
2134697,
2134692,
2134693,
2134694,
2134695,
2134698,
2134699,
2134700,
2134701

SELECT *
FROM mytable
WHERE ID IN (
    2134696,
    2134697,
    2134692,
    2134693,
    2134694,
    2134695,
    2134698,
    2134699,
    2134700,
    2134701
)

Execution Time: 0.03 seconds.

第一个查询应该和其他2一样快,但速度要慢得多。

任何人都可以解释为什么会这样,并提出更好的解决方案吗?

2 个答案:

答案 0 :(得分:2)

您首先查询正在进行两次表(或索引)扫描(数百万行)并将它们连接在一起以过滤行。

您的第二个和第三个查询正在执行单个表(或索引)扫描,但他们没有将它们连接在一起。

你应该使用类似的东西:

SELECT *
FROM (
    SELECT r.*, ROWNUM rnum
    FROM (
        SELECT *
        FROM   mytable
        ORDER BY ID
    ) r
    WHERE ROWNUM <= 1000010
)
WHERE rnum >= 1000001

只有一张表扫描。

Oracle 12c中,您可以使用:

SELECT   *
FROM     MYTABLE
ORDER BY id 
OFFSET 1000000 ROWS FETCH NEXT 10 ROWS ONLY

答案 1 :(得分:0)

获取总记录数和记录的最佳方式。

更改[YOURTABLENAME] 改变2和100(2“PAGENO”,100“PERPAGE”)

with 
XPARAMS as (select 2 "PAGENO", 100 "PERPAGE" from dual)
,P2 as (select  (XPARAMS.PAGENO-1)*XPARAMS.PERPAGE "STARTNO",   XPARAMS.PAGENO*XPARAMS.PERPAGE "ENDNO" from XPARAMS)
,D1 as (select  * from [YOURTABLENAME] t order by ID)
,DCOUNT as (select count(*) "TOTALCOUNT" from D1)
,D2 as (select  rownum "RN" , D1.* from D1 )
,D3 as (select D2.* from D2,P2 where D2.RN between P2.STARTNO and p2.ENDNO )
select D3.RN, DCOUNT.TOTALCOUNT, XPARAMS.PAGENO, XPARAMS.PERPAGE, D3.* from D3,DCOUNT, XPARAMS