表具有从序列生成的代理主键。不幸的是,这个序列用于为其他一些表生成密钥(我没有设计它,我也无法改变它)。
在Oracle中选择最后n
个插入记录的最快方法是什么,按ID降序排列(最后插入到顶部)?
n
是一些相对较小的数字 - 页面上显示的记录数量 - 可能不超过50个。
表现在有30.000.000条记录,每天有10-15,000条新记录。
数据库是Oracle 10g。
修改
回答一条评论:这个问题的动机是查询的执行计划:
select * from MyTable order by primarykeyfield desc
执行计划是:
---------------------------------------------
| Id | Operation | Name |
---------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | SORT ORDER BY | |
| 2 | TABLE ACCESS FULL| MyTable |
---------------------------------------------
我很惊讶Oracle希望在排序字段上有索引时执行全表扫描和排序。
来自已接受答案的查询使用索引并避免排序。
编辑2:
回覆。 APC的评论:排序是让我感到惊讶的一部分。我预计Oracle会使用index来按预期顺序检索行。查询的执行计划:
select * from (select * from arh_promjene order by promjena_id desc) x
where rownum < 50000000
使用索引而不是全表访问和排序(通知条件rownum < 50.000.000
- 这比表中的记录数量多,Oracle知道它应该从表中检索所有记录)。此查询将所有行作为第一个查询返回,但具有以下执行计划:
| Id | Operation | Name |
-------------------------------------------------------
| 0 | SELECT STATEMENT | |
|* 1 | COUNT STOPKEY | |
| 2 | VIEW | |
| 3 | TABLE ACCESS BY INDEX ROWID| MyTable |
| 4 | INDEX FULL SCAN DESCENDING| SYS_C008809 |
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<50000000)
对我而言,Oracle正在为这两个基本上返回相同结果集的查询创建不同的执行计划。
编辑3: Re Amoq的评论:
你确定吗?在最多9个Oracle版本中,建议不时手动刷新统计信息。从版本10开始,Oracle会自动更新统计信如果Oracle不将其用于查询优化,那么统计数据的用途是什么?Oracle不知道50M是 大于行数。当然, 它有统计数据,但它们可能是 古老而错误 - 而甲骨文永远不会 允许自己传递错误 结果只是因为统计数据 错。
答案 0 :(得分:15)
使用ROWNUM
:
select
*
from
(
select
*
from
foo
order by
bork
) x
where
ROWNUM <= n
请注意,{<1}}在排序子查询之前应用,这就是您需要两个嵌套查询的原因,否则您只会得到rownum
个随机行。
答案 1 :(得分:4)
它会被更多次查看而不是更新吗?如何保留最后N个插入行的ID的另一个表(使用触发器从该表中删除最小的ID并添加一个当前插入的新行)。
您现在有一个表记录了最后N个插入行的ID。任何时候你想要N,只需将它加入主表。如果N改变,选择它可以的最大值,然后在...之后过滤它...当然你可能发现你的应用程序不是那么快(维护这个表可能会抵消任何性能提升)
答案 2 :(得分:4)
如果您没有严格增加的字段,您还可以使用ORA_ROWSCN(系统更改编号)作为其近似值。
select * from (select * from student order by ORA_ROWSCN desc) where rownum<10
警告:这不准确,因为Oracle每个块只记录一个SCN,而不是每行。它似乎也做了全表扫描 - 可能oracle不够聪明,无法优化这种类型。因此,这可能不适合生产使用。
答案 3 :(得分:3)
如果您不知道字段名称或表名称以外的任何内容,这可能对您有帮助。
select * from (
select * from(
select rownum r,student.* from student where rownum<=(
select max(rownum) from student
)
) order by r desc
) where r<=10;
答案 4 :(得分:3)
尝试执行index_desc提示
select /*+ index_desc(MyTable,<PK_index>) */ * from MyTable order by primarykeyfield desc