我正在使用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一样快,但速度要慢得多。
任何人都可以解释为什么会这样,并提出更好的解决方案吗?
答案 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