Oracle IO问题解析

OracleIO的产生

IO当然包括了读、写两部分,先介绍 Oracle 中写操作的产生。

介绍写操作之前,先简单的看下 Oracle 的物理结构:oracle的物理文件包括以下三种文件:控制文件( Control Files)、重做日志文件( Redo Log Files)、数据文件( datafiles)。而数据文件中,根据功能的不同,还可以分为系统数据文件、临时空间文件、 回滚段文件和用户数据文件。另外,如果数据库的 Archive Log模式被激活,还存在归档日志文件。 Oracle的 IO产生,就是对这些文件的数据读、写操作。下面再详细看下几种主要写操作的产生及其过程。

控制文件

控制文件中记录了整个数据库的物理结构信息,如数据库名字、数据文件及日志文件名字和位置、事件 戳信息 等等。任何数据库的结构变化(如果创建新的数据文件)都会引起Oracle修改控制文件。同时控制文件还记录系统和各个数据文件的 SCN( System Change Number,关于 SCN可以参见文章《 Oracle SCN 机制详解 》)信息,以用于数据恢复,因此数据文件上的 SCN变化后, Oracle也会相应修改控制文件上的 SCN信息。

用户数据修改

由于内存的读写效率比磁盘的读写效率高万倍,因此,为了降低 IO wait oracle会将数据cache在内存( Buffer Cache,对 Buffer Cache的详细介绍可以参见《 Oracle 内存全面分析 》)中,对数据的读写尽量在内存中完成。当 BufferCache中的数据缓存块被修改过了,它就被标记为“脏”数据。根据 LRU( Least Recently Used)算法,如果一个数据 块最近很少被使用,它就称为“冷”数据块。进程 DBWn(系统中可以存在多个 DBW进程, n为序号)负责将“冷”的“脏”数据写入数据文件中去。 DBWn 进程会在以下两种情况下将“脏”数据写入磁盘中去:

 

当服务进程扫描一定数量(阀值)的 Buffer Cache 后还没有找到干净、可重用的缓存块后,它会通知 DBWn 进程将“脏”数据写入文件中去,以释放出空闲缓存;

当发生检查点(Checkpoint)时。

Redo Log

在非直接写( Direct Write )的情况下,事务中的写操作都会产生Redo Log,作为数据块异常关闭时的恢复记录。同样,和 写用户数据类似, Redo Log也不会被直接写入 Redo Log文件,而是先写入 Log Buffer中。

Log Buffer是一个可以循环重用的缓存区。 LGWR 进程负责将Log Buffer中的记录写入 Redo Log File中去。一旦 Log Buffer中的条目被写入了 Redo Log文件中,就可以被重用了。

为了保证事务尽快获得LogBufferLGWR进程一般会尽快将Log Buffer中的数据写入 Redo Log 文件中去。在以下几种情况下,LGWR回将一个连续的 Log Buffer写入 Redo Log文件中去:

 

当一个事务提交( COMMIT)时;

3秒钟写一次 Log Buffer

Log Buffer到达 1/3满时;

DBWn进程将“脏”数据写入磁盘时;

 

Archive Log

当据库 的 Archive Log 模式被激活后,所有Redo Log数据都会被写入 Archive Log文件中以便日后进行恢复。当发生日志组切换时, ARCn Archive进程,可以存在多个)进程就会 Redo Log文件拷贝到指定存储目录中去,成为 Archive Log文件。

临时表空间

当 Oracle 在执行一些SQL时,会需要一些临时空间来存储执行语句时产生的中间数据。这些临时空间由 Oracle从指定的临时 表空间中分配给进程。主要有三种情况会占用临时空间:临时表 /索引操作、排序和临时 LOB操作。

 

临时表 /索引

在会话中,当第一次对临时表进行 INSERT (包括CTAS)时,Oracle会从临时 表空间中为临时表及其索引分配临时空间 存储数据。

 

排序

任何会使用到排序的操作,包括 JOIN 、创建(重建)INDEXORDERBY、聚合计算(GROUP BY)以及统计数据收集,都可能使用到临时表空间。

排序操作首先会选择在内存中的SortArea进行(Sort In Memory),一旦SortArea不足,则会使用临时空间进行排序操作(Sort In Disk)。看以下例子:

 

SQL> altersession set sort_area_size = 10000000;

 

Session altered.

 

SQL> selectowner, object_name from t_test1

  2   order by object_id;

 

47582 rows selected.

 

Execution Plan

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

Plan hash value:1312425564

 

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

| Id   | Operation          |Name    | Rows  | Bytes | Cost (%CPU)|Time     |

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

|   0 |SELECT STATEMENT   |        | 47582 |  1486K|   155   (4)| 00:00:02 |

|   1 |   SORT ORDER BY    |         | 47582 | 1486K|   155   (4)| 00:00:02 |

|   2|   TABLE ACCESS FULL| T_TEST1 | 47582 |  1486K|  150   (1)| 00:00:02 |

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

 

 

Statistics

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

         1  recursive calls

         0  db block gets

       658  consistent gets

         0  physical reads

         0  redo size

   1566184  bytes sent via SQL*Net to client

     35277  bytes received via SQL*Net from client

      3174  SQL*Net roundtrips to/from client

         1  sorts (memory)

         0  sorts (disk)

     47582  rows processed

 

SQL> altersession set sort_area_size = 10000;

 

Session altered.

 

SQL> selectowner, object_name from t_test1

  2   order by object_id;

 

47582 rows selected.

 

Execution Plan

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

Plan hash value:1312425564

 

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

| Id   | Operation          |Name    | Rows  | Bytes |TempSpc|Cost (%CPU)| Time|

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

|   0 |SELECT STATEMENT   |        | 47582 |  1486K|      |  1251   (1)| 00:0

0:16 |

|   1 |   SORT ORDER BY    |         | 47582 |  1486K| 4136K|  1251   (1)| 00:0

0:16 |

|   2|   TABLE ACCESS FULL| T_TEST1 | 47582 | 1486K|       |   150  (1)| 00:0

0:02 |

 

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

 

Statistics

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

         6  recursive calls

        20  db block gets

       658  consistent gets

       629  physical reads

         0  redo size

   1566184  bytes sent via SQL*Net to client

     35277  bytes received via SQL*Net from client

      3174  SQL*Net roundtrips to/from client

         0  sorts (memory)

         1  sorts (disk)

     47582  rows processed

 

临时 LOB对象

LOB对象包括 BLOB CLOBNCLOB、和 BFILE。在 PLSQL程序块中,如果定义了 LOB变量,则这些 LOB变量就是临时 LOB对象。临时 LOB对象被创建在临时 表空间上,直到 LOB数据被释放,或者会话结束。

回滚段

我们知道,一个事务在未被提交前,其做的任何修改都是可以被回滚( Rollback )的。这些回滚数据就被放到 回滚段( Rollback Segment)上。此外,一致性读( Read Consistency)、数据库恢复( Recover)都会用到 回滚段。

任何数据块的修改都会被记录在 回滚段 中,甚至Redo Log也会产生回滚记录。当任何一个非只读(只有查询)的事务开始时, oracle会自动为其指定下一个可用的 回滚段。事务中任何数据变化都被 写入回滚段中。如果事务回滚, oracle根据 回滚段中的 回滚记录buffercache中的“脏”数据恢复,释放 回滚段空间。当事务被提交,由于要保证一致性读, oracle并不会立即释放 回滚段中的数据,而是会保留一段时间。

1.1.7       Direct-PathInsert

这里,我们还要介绍一种特殊的写操作—— Direct-Path Insert (直接路径插入)。Direct-PathInsert通过直接在表中已存在的数据后面添加数据,直接将数据写入数据文件中,而忽略掉了BufferCache

我们前面提到,为了能在意外时恢复数据,每一个数据修改都会被记录到 Redo Log 中。然而,由于Redo Log需要写入到物理文件中去,是一个比较消耗性能的操作。为了提高性能,我们在批量写入数据时就可以通过 Direct-Path Insert的指定 NOLOGING的方式来避免写 Redo Log。

有多种方法可以指定 Direct-Path Insert CTAS( CREATE TABLE AS SELECT); SQL*Loader指定 Direct参数;在语句中指定 APPEND提示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值