代码之家  ›  专栏  ›  技术社区  ›  zendar

选择“n”表中最后插入的记录-Oracle

  •  6
  • zendar  · 技术社区  · 15 年前

    表具有从序列生成的代理主键。不幸的是,这个序列用于为其他一些表生成键(我没有设计它,也无法更改它)。

    最后选择哪一个最快 n 在Oracle中插入记录,按ID降序排列(最后插入在顶部)?

    n 是一些相对较小的数字-要在页面上显示的记录数-可能不大于50。

    现在,Table有30000.000条记录,每天有10000到15000条新记录。

    数据库是Oracle10g。

    编辑:
    回答一句话:这个问题的动机是执行查询计划:

      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将使用索引按预期的顺序检索行。查询执行计划:

    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: 回复AMOQ的评论:

    甲骨文不知道5000万是 大于行数。当然, 它有统计数据,但它们可能是 旧的和错误的-和甲骨文永远不会 允许自己传递错误的 结果只是因为统计数据 错了。

    你确定?在最多9个Oracle版本中,建议不时手动刷新统计信息。从10版开始,Oracle会自动更新统计信息。如果Oracle不使用统计数据进行查询优化,那么统计数据的用途是什么?

    5 回复  |  直到 10 年前
        1
  •  15
  •   Donnie    15 年前

    使用 ROWNUM :

    select
      *
    from
      (
        select
          *
        from
          foo
        order by
          bork
       ) x
    where
      ROWNUM <= n
    

    注意 rownum 已应用 之前 为子查询排序,这就是为什么您需要两个嵌套查询,否则您将得到 n 随机行。

        2
  •  4
  •   debracey    12 年前

    它的浏览次数会比更新次数多吗?如何保留最后n个插入行的ID的另一个表(使用触发器从该表中删除最小的ID,并添加一个具有当前插入的新行)。

    现在,您有一个表记录最后n个插入行的ID。只要你想要n,就把它加入主表。如果n改变,选择最大值,然后在…之后过滤它。当然,你可能会发现你的应用程序速度不够快(维护此表可能会抵消任何性能提升)

        3
  •  4
  •   Dr. Hans-Peter Störr    10 年前

    在没有严格递增字段的情况下,也可以使用 ORA_ROWSCN (系统变化数)作为近似值。

    select * from (select * from student order by ORA_ROWSCN desc) where rownum<10
    

    警告:这不准确,因为Oracle只记录每个块一个SCN,而不是每行一个。此外,它似乎做了一个完整的表扫描-可能甲骨文不够聪明,优化这类。因此,这可能不是生产使用的好主意。

        4
  •  3
  •   Grambot    12 年前

    如果您不知道字段名或表名以外的任何内容,这可能对您有所帮助。

    select * from (
      select * from(
        select rownum r,student.* from student where rownum<=(
          select max(rownum) from student
        )
      ) order by r desc
     ) where r<=10;
    
        5
  •  3
  •   shank    11 年前

    尝试执行索引描述提示

    select /*+ index_desc(MyTable,<PK_index>) */ * from MyTable order by primarykeyfield desc