Oracle 表缓存(caching table)的使用

本文探讨了在Oracle数据库中使用缓存表(caching table)和Keep Buffer Pool的策略,旨在减少全表扫描带来的频繁I/O操作,通过将热点数据保持在内存中,提升数据库性能。文章详细介绍了缓存表的工作原理,包括如何通过LRU和MRU策略避免数据块过早淘汰,以及如何使用SQL提示、ALTER TABLE和CREATE TABLE语句创建缓存表。此外,还对比了缓存表与pin对象的区别,以及缓存表与Keep Buffer Pool的异同。

1.使用caching table 的原因

        在通常的情况下,应用程序访问在cache中的数据块将按照LRU算法来进行处理。然而对于小表的访问,当使用全表扫描时,则该表

    中的块会放置LRU列表最近最少使用尾部的(LRU端),因此很快就被淘汰出局。然而使用基于成本优化的方法,对于小表进行查询以及收

    集统计信息,大多情形下走的是全表扫描,因此势必造成一种情形,即该表后续需要再次访问,而每次使用了全表扫描,而该对象很快

    被淘汰出局,因此需要再次读入到buffer cache,耗用了大量的I/O。

           

2.解决该问题的方法

    设计表为caching table ,即使对该表使用全表访问时,则该表对象的块仍然被放置在LRU列表最近最多使用的尾部(MRU段)

    不要过度的使用caching table,以免造成性能下降

    通常将caching table 存放在keep buffer pool,缺省的情况下会放置在default buffer pool。

   

3.具有cache属性与pin 的差异

    对于具有cache属性的对象,并不是将该对象pin到cache里,而是尽可能的延迟该对象驻留cache的时间

    而对于pin对象,则是将该对象常驻到内存

   

4.设计cache table 的方法

    创建表对象时,使用cache子句

    修改表对象时,使用cache子句

    使用cache 提示

   

    创建表对象时使用cache,如下面的例子

        create table tb_test

        (id number

         ,name varchar2(20)

         ,sex  char(1)

         ,age  number

         ,score number)

         tablespace users

         storage(initial 50k next 50k pctincrease 0)

         cache;    --指定cache子句

 

     使用alter table 修改已经存在的表

        alter table scott.emp cache;

       

     可以使用nocache来修改对象,使其不具备cache属性

        alter table soctt.emp nocache

       

     使用hint提示符来实现cache

        select /*+ cache*/ empno,ename from scott.emp;

   

5.使用例子演示caching table情形

 

    scott@ORCL> create table tb1 nologging

      2  as select level id,rpad('*',4000,'*') data,rpad('*',2000,'*') data2

      3  from dual

      4  connect by level <= 15000;

 

    Table created. 

 

    scott@ORCL> create table tb2

      2  cache nologging

      3  as select level id,rpad('*',4000,'*') data,rpad('*',2000,'*') data2

      4  from dual

      5  connect by level <= 15000;

 

    Table created.

 

    scott@ORCL> select count(1) from tb1;

 

      COUNT(1)

    ----------

         15000

 

    scott@ORCL> select count(1) from tb2;

 

      COUNT(1)

    ----------

         15000

 

    scott@ORCL> select table_name,num_rows,cache from user_tables where table_name in ('TB1','TB2');

 

    TABLE_NAME        NUM_ROWS CACHE

    --------------- ---------- -----

    TB1                  15000     N

    TB2                  15000     Y

         

    scott@ORCL> set autotrace traceonly statistics;

    scott@ORCL> select count(1) from tb1;

 

    Statistics

    ----------------------------------------------------------

              5  recursive calls

              0  db block gets

          15086  consistent gets

          15000  physical reads

              0  redo size

            412  bytes sent via SQL*Net to client

            385  bytes received via SQL*Net from client

              2  SQL*Net roundtrips to/from client

              0  sorts (memory)

              0  sorts (disk)

              1  rows processed

             

    scott@ORCL> select count(1) from tb1;

 

    Statistics

    ----------------------------------------------------------

              0  recursive calls

              0  db block gets

          15011  consistent gets

          15000  physical reads

              0  redo size

            412  bytes sent via SQL*Net to client

            385  bytes received via SQL*Net from client

              2  SQL*Net roundtrips to/from client

              0  sorts (memory)

              0  sorts (disk)

              1  rows processed    

 

    scott@ORCL> select count(1) from tb2;

 

    Statistics

    ----------------------------------------------------------

              0  recursive calls

              0  db block gets

          15011  consistent gets

            197  physical reads

              0  redo size

            412  bytes sent via SQL*Net to client

            385  bytes received via SQL*Net from client

              2  SQL*Net roundtrips to/from client

              0  sorts (memory)

              0  sorts (disk)

              1  rows processed

 

    scott@ORCL> select count(1) from tb2;

 

    Statistics

    ----------------------------------------------------------

              0  recursive calls

              0  db block gets

          15011  consistent gets

              0  physical reads

              0  redo size

            412  bytes sent via SQL*Net to client

            385  bytes received via SQL*Net from client

              2  SQL*Net roundtrips to/from client

              0  sorts (memory)

              0  sorts (disk)

              1  rows processed      

   

        从上面的示例中可以看出,表tb1每次都将使用相同的物理读,而表tb2一旦被load进buffer cache中,始终处于LRU的MRU端,尽可能的

    避免因buffer cache过小而被置换到buffer cache之外。

        注意不同的演示环境可能有所差异,本人的演示环境如下;

            scott@ORCL> show parameter sga_

 

            NAME                                 TYPE        VALUE

            ------------------------------------ ----------- ------------------------------

            sga_max_size                         big integer 264M

            sga_target                           big integer 264M

            scott@ORCL> select * from v$version;

 

            BANNER

            ----------------------------------------------------------------

            Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

            PL/SQL Release 10.2.0.1.0 - Production

            CORE    10.2.0.1.0      Production

            TNS for Linux: Version 10.2.0.1.0 - Production

            NLSRTL Version 10.2.0.1.0 - Production         

         

6.注意cache table与keep buffer pool的异同

    两者的目的都是尽可能将最热的对象置于到buffer pool,尽可能的避免aged out。

    cache table是将对象置于到default buffer cache。

    而使用buffer_pool keep子句是将对象置于到keep buffer pool。

    当buffer_pool和cache同时指定时,keep比cache有优先权。buffer_pool用来指定存贮使用缓冲池,而cache/nocache指定存储的

    方式(LRU或MRU端)。建表时候不注明的话,nocache是默认值。

<think>我们正在处理Oracle错误代码22905的问题。 错误22905通常与Oracle的"SecureFiles LOB"功能相关,特别是在尝试修改或访问LOB数据时可能出现。 根据Oracle文档,错误22905示"cannot read from non-SecureFiles LOB when the default caching is changed"。 这意味着在默认缓存设置被更改的情况下,尝试从一个非SecureFiles LOB读取数据。 常见原因: 1. 数据库升级后,原有的LOB列仍然是BASICFILE格式,而新的设置要求使用SECUREFILE。 2. 在ALTER TABLE语句中修改了LOB的缓存设置(例如CACHE或NOCACHE),但该LOB列不是SECUREFILE格式。 解决方案: 1. 将LOB列迁移到SECUREFILE格式: 在Oracle 11g及以上版本中,可以使用MOVE语句将LOB列转换为SECUREFILE。 例如: ```sql ALTER TABLE your_table MOVE LOB(your_lob_column) STORE AS SECUREFILE (TABLESPACE your_tablespace); ``` 注意:这需要足够的空间,并且在操作期间会锁定。 2. 避免修改非SECUREFILE LOB的缓存设置: 如果不需要改变缓存设置,就不要执行相关的ALTER语句。 3. 另一种方法是重新创建,将LOB列定义为SECUREFILE: 使用CREATE TABLE AS SELECT (CTAS)方式创建新,并在定义中指定SECUREFILE,然后将数据导入。 4. 检查数据库参数: 确保数据库参数`db_securefile`设置为允许使用SECUREFILE(如PERMITTED,这是默认值)。 示例步骤: 假设名为`DOCUMENTS`,LOB列名为`CONTENT`: ```sql -- 检查LOB存储类型 SELECT table_name, column_name, securefile FROM user_lobs WHERE table_name = 'DOCUMENTS'; -- 如果SECUREFILE列为'NO',则迁移 ALTER TABLE DOCUMENTS MOVE LOB(CONTENT) STORE AS SECUREFILE (CACHE); ``` 注意事项: - 迁移操作可能需要较长时间,特别是对于大,应在低峰期进行。 - 确保有足够的空间。 - 迁移后,重建索引(如果有LOB索引的话)。 - 如果有分区,则需要为每个分区单独迁移。 如果问题仍然存在,请检查相关的ALTER语句是否确实修改了非SECUREFILE LOB的缓存设置。 §§相关问题§§ 1. Oracle中BASICFILE和SECUREFILE LOB的主要区别是什么? 2. 如何查询数据库中所有LOB列的存储类型(BASICFILE或SECUREFILE)? 3. 在迁移LOB到SECUREFILE时,如何避免长时间锁定? 4. 除了22905错误,还有哪些常见的LOB操作错误? 5. 如何配置Oracle参数以完全禁用SECUREFILE? </think>### Oracle 错误 ORA-22905 详解及解决方法 **错误说明**: ORA-22905 错误示"无法从非结构化数据类型中访问行"。该错误通常发生在尝试直接访问 **Oracle VARRAY 或嵌套** 的元素时,未使用正确的转换函数(如 `TABLE()` 函数)。 #### 常见场景 1. 直接查询 VARRAY/Nested Table 列: ```sql SELECT phone_list FROM contacts WHERE contact_id = 1; -- 错误:ORA-22905: 无法访问非结构化数据类型中的行 ``` 2. 在 WHERE 子句中直接引用集合元素: ```sql SELECT * FROM contacts WHERE phone_list(1) = '13800138000'; -- 触发 ORA-22905 ``` --- ### 解决方法(三种方案) #### 方案 1:使用 `TABLE()` 函数解包集合 ```sql SELECT t.phone_number FROM contacts c, TABLE(c.phone_list) t -- 关键解包操作 WHERE c.contact_id = 1; ``` #### 方案 2:在 PL/SQL 中处理(推荐批量操作) ```sql DECLARE v_phones VARCHAR2(100); BEGIN SELECT COLUMN_VALUE INTO v_phones FROM TABLE(SELECT phone_list FROM contacts WHERE contact_id = 1) WHERE ROWNUM = 1; DBMS_OUTPUT.PUT_LINE('第一号码:' || v_phones); END; ``` #### 方案 3:创建支持索引的类型(长期方案) 1. 创建可索引的集合类型: ```sql CREATE TYPE phone_array AS VARRAY(10) OF VARCHAR2(20); ``` 2. 修改结构: ```sql ALTER TABLE contacts MODIFY phone_list phone_array; ``` 3. 直接查询: ```sql SELECT phone_list(1) FROM contacts WHERE contact_id = 1; ``` --- ### 根本原因说明 | 数据类型 | 是否结构化 | 直接访问 | 解决方案 | |----------------|------------|-----------|------------------------| | VARRAY | ❌ 非结构化 | 禁止 | 必须使用 `TABLE()` | | Nested Table | ❌ 非结构化 | 禁止 | 必须使用 `TABLE()` | | 索引组织(IOT)| ✅ 结构化 | 允许 | 可直接访问 | --- ### 预防措施 1. **设计阶段**:优先使用可索引的集合类型(如 `VARRAY` 显示定义尺寸) 2. **查询规范**: - 所有集合操作必须通过 `TABLE()` 或 `CAST(MULTISET(...))` 3. **错误处理**: ```sql EXCEPTION WHEN ORA-22905 THEN DBMS_OUTPUT.PUT_LINE('错误:请使用TABLE()处理集合'); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值