我想从按日期排序的Oracle表中获取前N行。
执行此操作的常用方法,此解决方案会针对我在SO / google上找到的每个问题返回。
Select *
from
(select * from
myTable
ordered by Date desc)
where rownum < N
这个解决方案在我的情况下是不切实际的,因为myTable包含大量的行 导致Oracle花费太长时间来返回子查询中的所有行。
问题是,有没有办法限制子查询中返回的ORDERED行数?
答案 0 :(得分:12)
您推断Oracle必须在过滤掉前N个之前返回子查询中的所有行是错误的。它将开始从子查询中获取行,并在返回N行时停止。
话虽如此,可能是Oracle需要从表中选择所有行并在它们开始返回之前对它们进行排序。但是,如果在ORDER BY子句中使用了列的索引,则可能不会。
Oracle与任何其他DBMS处于相同的位置:如果您有一个没有索引的大型表,那么在没有先获取所有行和排序的情况下,它怎么可能知道哪些行是前N个它们?
答案 1 :(得分:2)
问题是,有没有办法限制ORDERED行的数量 在子查询中返回?
以下是我通常用于top-n类型查询的内容(在这种情况下是分页查询):
select * from (
select a.*, rownum r
from (
select *
from your_table
where ...
order by ...
) a
where rownum <= :upperBound
)
where r >= :lowerBound;
我通常使用索引列对内部查询进行排序,而使用rownum意味着Oracle可以使用count(stopkey)优化。所以,不一定要进行全表扫描:
create table t3 as select * from all_objects;
alter table t3 add constraint t_pk primary key(object_id);
analyze table t3 compute statistics;
delete from plan_table;
commit;
explain plan for
select * from (
select a.*, rownum r
from (
select object_id, object_name
from t3
order by object_id
) a
where rownum <= 2000
)
where r >= 1;
select operation, options, object_name, id, parent_id, position, cost, cardinality, other_tag, optimizer
from plan_table
order by id;
你会发现Oracle使用t_pk进行完整的索引扫描。另请注意使用stopkey选项。
希望这能解释我的答案;)
答案 2 :(得分:1)
如果您有大量数据,则排序可能会变得繁重。看看你的执行计划。如果数据不是实时数据,您可以在这些选择中创建材质视图......
答案 3 :(得分:0)
在旧版本的ORACLE(8.0)中,您无法在子查询中使用ORDER BY子句。 因此,仅对于那些还使用某些古老版本的人而言,还有另一种应对方式:UNION运算符的魔力。 UNION将按查询中的列对记录进行排序:
示例:
SELECT * FROM
(SELECT EMP_NO, EMP_NAME FROM EMP_TABLE
UNION
SELECT 99999999999,'' FROM DUAL)
WHERE ROWNUM<=5
where 99999999999 is bigger then all values in EMP_NO;
或者,如果您要选择薪水最高的5位薪水最高的5名员工:
SELECT EMP_NO, EMP_NAME, 99999999999999-TMP_EMP_SAL
FROM
(SELECT 99999999999999-EMP_SAL TMP_EMP_SAL, EMP_NO, EMP_NAME
FROM EMP_TABLE
UNION
SELECT 99999999999999,0,'' FROM DUAL)
WHERE ROWNUM<=5;
此致
Virgil Ionescu