【问题标题】:How does one store the result of a repeated query in memory in Oracle?如何将重复查询的结果存储在 Oracle 的内存中?
【发布时间】:2020-03-27 13:04:41
【问题描述】:

为了准备数据库架构迁移,在该迁移中我使用 ON CASCADE DELETE 添加大量外键约束,我需要运行清除孤立行的数据迁移。数据迁移目前看起来像这样

delete from child1 where parent_id not in (select id from parent)
delete from child2 where parent_id not in (select id from parent)
...
delete from child50 where parent_id not in (select id from parent)

(是的,有 50 个这样的表。)parent 是一个具有足够记录的表,因此最好不必对它多次运行 id 查询;我宁愿运行一次,存储结果,然后根据存储的查询结果检查子表的值。

我找到了有关“临时表”的文档,这听起来像是我想要的。在 MySQL 中,我相信我可以将 engine=memory 指定为 CREATE TABLE 语句的一个选项,以防止表存储在磁盘上。我没有看到在 Oracle 中做同样事情的方法。

我有哪些选项可以对select id from parent 查询的结果进行内存缓存?

【问题讨论】:

    标签: sql oracle performance caching


    【解决方案1】:

    Oracle 使用多种类型的缓存,您可能不需要做任何事情,PARENT.ID 就会自动缓存。

    缓冲区缓存是最大、最重要的缓存,它包含数据块(通常为 8KB)。缓冲区高速缓存可以包含来自表或索引的块。由于 Oracle 能够直接从索引中读取,而无需使用表,它可以只缓存 ID 值的索引块,这应该很好地适合内存。

    下面的测试用例显示了一个简单的父/子表,其中 Oracle 缓存了 ID 上 100% 的索引,50 个查询中有 49 个将完全从内存中读取。

    创建父/子表,添加 100K 样本行,收集优化器统计信息以获得最佳执行计划。

    create table parent(id number, a varchar2(100), b varchar2(100),
        constraint parent_pk primary key(id));
    insert into parent select level, 'aaaaaaaaaa', 'bbbbbbbbbb' from dual connect by level <= 100000;
    
    create table child(id number primary key, parent_id number,
        constraint child_fk foreign key (parent_id) references parent(id));
    insert into child select level, level from dual connect by level <= 100000;
    
    commit;
    
    begin
        dbms_stats.gather_table_stats(user, 'PARENT');
        dbms_stats.gather_table_stats(user, 'CHILD');
    end;
    /
    

    执行计划有一个 INDEX FAST FULL SCAN,它使用索引就像一个瘦表。

    explain plan for
    select * from child where parent_id not in (select id from parent);
    
    select * from table(dbms_xplan.display);
    
    Plan hash value: 3673552324
    
    --------------------------------------------------------------------------------------
    | Id  | Operation                | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT         |           |  1000 | 15000 |   125   (4)| 00:00:01 |
    |*  1 |  HASH JOIN RIGHT ANTI SNA|           |  1000 | 15000 |   125   (4)| 00:00:01 |
    |   2 |   INDEX FAST FULL SCAN   | PARENT_PK |   100K|   488K|    53   (2)| 00:00:01 |
    |   3 |   TABLE ACCESS FULL      | CHILD     |   100K|   976K|    70   (3)| 00:00:01 |
    --------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - access("PARENT_ID"="ID")
    

    运行一次查询

    select * from child where parent_id not in (select id from parent);
    

    索引的每个块都被缓存。下一次运行将从内存中读取数据。

    --Number of cached blocks for PARENT_PK: 256
    select count(distinct block#)
    from v$bh
    where objd = (select object_id from dba_objects where object_name = 'PARENT_PK')
    order by class#;
    
    
    --Total number of blocks for PARENT_PK: 256
    select blocks
    from dba_segments
    where segment_name = 'PARENT_PK';
    

    种方法可以将结果存储在内存中,就像结果缓存一样。但是对于您描述的问题,您可能不需要做任何事情来实现近乎完美的缓存。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-12
      • 1970-01-01
      • 1970-01-01
      • 2013-05-19
      • 1970-01-01
      • 2021-12-28
      • 2011-07-02
      • 2021-11-09
      相关资源
      最近更新 更多