1、DB的存储层次(在其他文章中已经介绍过了,这里只是简述)
1)blocks:是data file I/O的最小单位,也是空间分配的最小单位。一个Oracle block是由一个或多个连续的OS blocks组成。
2)extents:是由多个连续的data blocks组成的拥有存储空间分配的逻辑单位。一个或多个extents组成了一个segment。当在一个segment中的所有空间都被用完时,Oracle server会给segment分配新的extent。
3)segments:一个segment是一个extents的集合,存放了tablespace中具体的逻辑存储结构的所有数据。例如,每个 table,Oracle server会分配一个或多个extents用于组成该table的data segments。对于indexes,Oracle server分配一个或多个extents用于组成index segment。
2、extents的分配:为了尽可能降低动态分配extent的弊端,应该如下:
* 使用本地管理表空间的方法。
* 适当的评估segments的大小:确定object的最大size;创建object时,选择恰当的存储参数用于分配足够的空间给相应的data。
* 监控segments的动态extend的情况。
select owner, table_name, blocks, empty_blocks from dba_tables where empty_blocks/(blocks+empty_blocks)<.1;
alter table hr.employees allocate extent;
①创建本地管理extents的tablespace,其实自9i以来,系统默认的表空间都是本地管理的表空间。
create tablespace tsp_name datafile ‘/path/datafile.dbf’ size nM
extent management local uniform size mM;
本地管理表空间在其datafile内部创建一个位图用于记录每个block的使用状态。当extent被分配或释放重用,bitmap的相应值会被修 改,用于显示其中blocks的新状态。这些修改不会产生rollback information,因为没有修改data dictionary。
②大extents的优点:DBA应该分配适当的size给segments和extents,一般原则是大extents优于小extents,主要表现在:
* large extents在一定程度上降低了segments动态的分配extents的可能性
* large extents可以稍微的提高I/O的性能,因为Oracle server从磁盘读取一个连续的large extent的多个blocks应该比从几个small extents不连续的blocks的速度快。为了避免分离的multiblock的读取,可以考虑将extents设置为 5*DB_FILE_MULTIBLOCK_READ_COUNT。但是对于不经常进行全表扫描的table,这种设置不会有太大的性能改观。
* 对于非常large的tables,OS在文件大小上的限制可能使DBA不得不将object分配到multiple extents。
* 使用index查找的性能不会受到index是否在一个或多个extents中的影响。
* Extent maps存放了某个segment中所有extents的信息。如果MAXEXTENTS设置为UNLIMITED,这些maps可以存放在多个 blocks中,从性能角度讲,应该尽可能在一次I/O中读取该extent map。此外多个extents也会降低dictionary的性能,因为每个extent都会占用dictionary cache的少量空间。
附注:①在ASSM表空间中,每个segment的 segment header都有一个extent map,记录着segment所属的所有extents的第一个块的位置和区的大小,如果segment header中容纳不下所有的extents信息,oracle会另外添加专门的extents map块,保存segment中extents的位置大小信息。全表扫描时oracle会根据extents map中所记录的信息,扫描高水标记之下的所有extents的所有blocks.每个extents map block都有一个指向下一个extents map block的地址,segment header中的extents map信息也有指向第一个extents map block的地址.也就是说所有的extents map block构成了一个链表.全表扫描时就依据这个链表中所记录的block的位置信息进行扫描.extents map的主要作用是用于全表扫描.
②FLM段(Free List Managed Segment),其段头存放着段中Extent的信息,包括Extent的起始地址,Extent的长度。如果由于segment扩展过 多,segment header不能容下所有EXTENT的信息,则会用新的称之为EXTENT MAP BLOCK的块来专门存放EXTENT的信息。段头与各Extent Map Block之间用链表形式连接起来。它与ASSM中的extent map链表作用不同。
③large extents的缺点:因为需要更多连续的blocks,Oracle server可能很难找到足够的连接的空间用于对其的分配。
3、高水位线(High-Water Mark)
在空间分配中,有两类空闲blocks:曾经被占用过,但相应的数据被删除了,这些blocks将被记录到相应的free list中,当有insert操作时进程reuse,在high-water mark以下;另一类是自分配给相应的segment后,从来没有被使用过的,所以在high-water mark之上。
①high-water mark:被记录在segment header block中;在segment被创建时设置:当插入rows时,每次增加five-block;truncate tables会重置high-water mark,但delete不会。
②在table level,可以将high-water 玛瑞咖之上的空间收回:
alter table t_name deallocate unused …
全表扫描中,Oracle server会读取high-water mark以下的所有blocks,high-water mark以上的空闲blocks不会影响性能。
③在cluster中,空间是为所有的cluster keys分配的,无论其是否含有data。分配的空间依靠cluster在创建时参数size指定的大小和cluster的类型:
* 在hash cluster中,因为hash keys的数量在cluster被创建是已经被确定了,所以每个hash key所占用的空间都在high-water mark之下。
* 在index cluster中,空间被分配给每个cluster index。
4、table statistics
可以使用analyze语句或是dbms_stats对table的当前状况进行统计并保存在数据字典中,随后通过查看dba_tables获得相关信息。
eg:
analyze table t_name compute statistics;
select num_rows, blocks, empty_blocks as empty, avg_space, chain_cnt, avg_row_len from dba_tables where table_name=’T_NAME’;
其中dba_tables中不同的字段具体含义如下:
Num_Rows – Number of rows in the table
Blocks – Number of blocks below the high-water mark of the table
Empty_blocks – Number of blocks above the high-water mark of the table
Avg_space – Average free space in bytes in the blocks below the highwater mark
Avg_row_len – Average row length, including row overhead
Chain_cnt – Number of chained, or migrated, rows in the table
Avg_space_freelist_blocks – The average freespace of all blocks on a freelist
Num_freelist_blocks – The number of blocks on the freelist
5、DBMS_SPACE包:可用于获得segments中的space的状态信息,常用的有以下两个procedures:
* UNUSED_SPACE:用于获得分配给object未使用的space。
* FREE_BLOCKS:用于获得object的空闲的space。在运行时,必须提供相应的FREELIST_GROUP_ID,一般使用1,除非你使用的是Oracle Parallel server。
该DBMS_SPACE包是由dbmsutil.sql创建的。
6、恢复表空间:
1)对于在high-water mark以下的空间:
方法一:export the table;drop or truncate the table;import the table
在选择是drop还是truncate的时候,要考虑:drop将table在data dictionary中的所有information删除,并且space被收回;而truncate没有,并保留了相应已经分配的space等待 reused;如果使用的是data dictionary管理tablespace,则影响空间收回与分配的时间开销的主要因素是extents的数量(而不是size);如果使用的是 drop方法,则考虑在import时使用compress选项,因为整个空间的分配可能不是在一个连续的大空间上。
方法二:alter table t_name move;此方法执行之后,所有相关的indexes都为unusable状态,必须rebuild。
2)对于在high-water mark之上的unused block可使用:alter table t_name deallocate unused语句进行收回。
7、DB的block size设置
1)减少访问block的数量,这是DB tuning的一个目标。DBA对此调节的方法主要有:增大block size;尽可能紧凑的将rows放在block中,避免row的迁移现象。
2)database block size是在DB创建时由参数DB_BLOCK_SIZE指定的,是I/O读取datafile的最小单元。当前有些OS允许block size达到64KB,可以查看相应的OS,从而调整DB的block size。block size一旦设置就不能改变,除非对DB重建或是duplicate,在9i中已经进行了相应的改进,可以使用多中block sizes,但是对于base data size仍不可变。DB的block size应该是OS的整数倍。如果application中有大量的全表扫描,可以考虑增大block size,但不要超过OS的I/O size。
3)小block size的优劣:
* 优:降低了block 的冲突;有利于small rows;有利于随机访问,因为可以在一定程度上提高buffer cache的利用率,特别是在内存资源不足的情况下。
* 劣:small blocks管理所用的空间开销大;每个block存放的row较少,也会加大I/O的开销;可能造成更多的index blocks被读入。
在OLTP环境中,经常存在large object的随机访问时,small blocks相对更好。
4)large block size的优劣:
* 优:所用的管理空间开销小,更多的空间可用于存放具体的data;有利于顺序的读取;有利于large rows;改善了index读取的性能,因为大的block可以降低index的level数量,从而减少I/O的次数。
* 劣:在OLTP环境中不利于index blocks,可能会引起index leaf blocks的争用冲突;如果存在大量随机访问可能会造成buffer cache的浪费。
在DSS环境中,连续读取大量数据操作较多,使用large block更好。
8、PCTREE和PCTUSED(具体内容在其他文章中介绍过了,这里不累述了)
只有两类DML语句可以影响free blocks和used blocks的数量:delete和update。
释放的空间在一个block中很可能不是连续的,Oracle server只在下面情况同时出现时进行free space的合并:insert或update操作试图向一个有足够空间的block中插入数据;free space存在碎片,以至于row piece无法被写入。
具体设置:
①PCTFREE:默认情况下是10;如果不存在update操作,可以使用0;PCTFREE = 100 * UPD / (Average row length)
②PCTUSED:默认是40;PCTUSED = 100 – PCTFREE – 100 * Rows * ( average row length) / block size
其中:
UPD = update操作平均增加的bytes数量。
average row length和rows都可以在analyze之后从dba_tables表中获得。
当对一个已经存在的表进行这两个参数的修改,不会有马上的影响,只是在后续的DML操作中才发生作用。
9、migration和chaining(具体原因也在其他的文章中介绍过了)
①migration和chaining对性能的影响:一方面,引起这两种现象的insert和update本身性能比较差;另一方面,在查询此类记录的操作会因为额外的I/O造成性能较差。
migration现象过的,主要是由于PCTFREE参数设置过低引起的,对此可以考虑增大该值。
②对两者的检测,主要是通过analyze相应的表,随后从dba_tables表中观察其chain_cnt字段。此外可以从v$sysstat视图或 是statspack report中的“instance activity stats for DB”获得“table fetch continued row”的值。
还可以收集每个表中发生了migration和chaining的具体的rows:首先执行utlchain.sql脚本创建chained_rows统计表,随后执行语句:
analyze table t_name list chained rows;
③消除migration rows:
* export/import
* alter table t_name move
* 执行迁移脚本,具体见Oracle 9i Performance Tuning SG的P398
• Find migrated rows using ANALYZE.
• Copy migrated rows to new table.
• Delete migrated rows from original table.
• Copy rows from new table to original table.
此方法执行时,必须注意与original table相关的外键约束,应将其disable。
10、索引的重组
在经常发生DML的table上,indexes往往是带来性能问题的原因。
在data blocks中,Oracle server会将delete row释放的空间重新分配给insert rows,但是对于index blocks,Oracle server的应用时连续的。即使一个index block中只有一个index,也要维护该block。如果删除了block中的所有index,该block才会被送入free list。因此,必要时需要进行index的rebuild。
①对index space的监控:
* analyze index i_name validate structure;
* select name, (del_lf_rows_len / lf_rows_len) * 100 as wastage from index_stats;
在index_stats视图中,各字段含义如下:
• Lf_rows – Number of values currently in the index
• Lf_rows_len – Sum of all the length of values, in bytes
• Del_lf_rows – Number of values deleted from the index
• Del_lf_rows_len – Length of all deleted values
note:index_stats视图只保存最近一次analyze的结果,并且当前session只能看到当前session的分析结果。
* alter index emp_name_ix rebuild;
* alter index emp_name_ix coalesce;
如果如果已删除的index 记录超过20%,则应该选用rebuild。
rebuild会以原有的index作为基础,重建索引,可以重新指定STORAGE, TABLESPACE, INITRANS参数,同时可以用下面的参数加快重建的效率:
* PARALLEL/NOPARALLEL(NOPARALLEL是默认值)
* RECOVERABLE/UNRECOVERABLE ( RECOVERABLE是默认的):当使用unrecoverable时速度将更快,因为它不产生redo log,只在index创建是起作用,而不是设置参数,不记录到dictionary中。它使用隐含式的logging参数,意味着在index创建结束 后插入index项时,仍然会记录redo log。
* LOGGING/NOLOGGING:如果设置为NOLOGGING,该参数表明在index运行使用期间,将不产生任何redo log。它将记录到dictionary中。可以用alter index 进行修改。
注意:unrecoverable和logging是不兼容的。
alter index rebuild要快于index的drop后re-create,因为它使用了full scan的方法。
②监控index的使用情况
* EXECUTE DBMS_STATS.GATHER_INDEX_STATS(‘SECHMA_NAME’, ‘T_NAME’);
* create index … compute statistics;
* alter index .. rebuild compute statistics;
③此外,还可以用下面的方法查看没有使用的index:
从9i开始,对index的使用情况可以被收集到视图v$object_usage中。辅助DBA删除未使用的index,提高性能:
* 打开监控:alter index i_name monitoring usage;
* 停止监控:alter index i_name nomonioring usage;
随后查看v$object_usage:select index_name, used from v$object_usage;
在v$object_usage中各个字段的意义:
• index_name – The index name
• table_name – The corresponding table
• monitoring – Indicates whether monitoring is “ON or OFF”
• used – Indicates (YES or NO) the index has been used during the monitoring time
• start_monitoring – Time at which monitoring began on index
• stop_monitoring – Time at which monitoring stopped on index