简体   繁体   English

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

[英]Oracle paging on large table using list of primary keys

I'm using Oracle 11.2 and am trying to write a paging query on a table with millions of rows in it. 我正在使用Oracle 11.2,并试图在其中具有数百万行的表上编写分页查询。 Reading other articles I think I've found the best approach but it slows down the higher the page number is. 阅读其他文章,我认为我找到了最好的方法,但是页数越高,它的速度就越慢。

This is my solution. 这是我的解决方案。 First I get a list of primary key values (ID) for that page of data. 首先,我获得了该数据页面的主键值(ID)的列表。 I then get all the other table data matching those ids. 然后,我得到所有其他与这些ID匹配的表数据。 However this still runs slowly. 但是,它仍然运行缓慢。

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
 )

Execution Time: 30+ seconds. 执行时间:30+秒。

If I do the inner query separately and manually pass the ids to the outer query it's much faster: 如果我分别进行内部查询,然后将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.

The first query should be as fast as the other 2 together but it's much slower. 第一个查询应该和其他两个查询一样快,但是要慢得多。

Can anyone explain why this is and suggest a better solution? 谁能解释这是为什么,并提出更好的解决方案?

You first query is doing two table (or index) scans (of millions of rows) and joining them together to filter the rows. 您的第一个查询是对两个表(或索引)进行扫描(数百万行),并将它们结合在一起以过滤行。

Your second and third queries are doing a single table (or index) scan each but they are not joining them together. 您的第二个和第三个查询正在对单个表(或索引)进行扫描,但是它们没有将它们连接在一起。

You should use something like: 您应该使用类似:

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

Which only does a single table scan. 仅扫描单个表。

In Oracle 12c you can use: Oracle 12c中 ,可以使用:

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

Best way for get total records count and records. 获取总记录计数和记录的最佳方法。

change [YOURTABLENAME] change 2 and 100 ( 2 "PAGENO", 100 "PERPAGE" ) 更改[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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM