事务与撤销段
在某个事务启动时,ORACLE会为其指派一个(并且只能指派一个)撤销段。任何事务生成的撤销数据都无法被分配到多个撤销段中。如果某个事务生成的撤销数据填满了自己使用的撤销段,则ORACLE会自动为该撤销段添加另一个区间,从而使这个事务能够继续进行。虽然多个事务可以共享一个撤销段,但在数据库正常运行时就不会发生这种情况。
撤销管理的一个特性是ORACLE会根据需要自动生成新的撤销段,从而能够尽可能地确保多个事务不必共享撤销段。同样也会自动缩小或删除撤销段。
在某个事务更新表和索引数据块时,回滚该变化所需的信息会被写入指定撤销表空间的数据块。所有撤销数据一直会被保持至事务被提交。在默认情况下,ORACLE不会保证ACID测试的一致性,只能在一定的程度上保证一致性:某个查询成功,则查询结果会与这个查询开始时的数据库的状态一致。但能绝对保证ACID测试的原子性。撤销数据被分为两部分:Active撤销是回滚当前事务可能需要的撤销数据,在事务结束之前,这些数据不会被重写;Expired撤销是指事务被提交后ORACLE不再需要保存的撤销数据,如果ORACLE需要为当前的其他事务提供空间,则可以重写这些数据。
撤销数据在提交后过期意味着可以采用循环方式使用撤销段。最终,撤销数据会填满整个撤销表空间。可以通过查询V$TRANSACTION视图(该视图将V$SESSION与DBA_ROLLBACK_SEGS的列连接在一起)来查看为每个事务所指派的段。
管理撤销
管理撤销的原则:应该始终存在允许所有事务继续进行的足够撤销空间,要求撤销表空间大到足以应付撤销需求的最坏情况;
应该始终存在保证查询成功的足够撤销数据,要求撤销表空间内存在额外的空间,这些空间能够存储读一致性可能需要的过期撤销数据,从而长时间运行的查询不会因为出现快照过旧ORA-1555错误而失败。
如果某个事务耗尽了撤销空间,则该事务就会由于ORA-30036无法扩展撤销表空间内的撤销段而失败。导致该错误的语句会回滚,但指定事务的剩余部分会保持不变并不被提交。当且仅当撤销表空间被过期的撤销数据完全填满时才会引发这个错误条件。如果某个查询由于快照过旧而导致一致读失败,就意味着该查询会涉及一个在查询开始后发生变化的数据块,但当进入该撤销段查找原有数据时,撤销数据已被重写。
UNDO_MANAGEMENT:默认值为manual,表示ORACLE根本不会使用撤销段。应用该设置必须完成大量创建和调整回滚段的工作;auto表示启用使用撤销段的自动撤销管理。该参数是静态的,意味着参数发生变化只有在重新启动实例后才能生效。
UNDO_TABLESPACE:启用UNDO_MANAGEMENT=auto后,就必须指定该参数。该参数指定了一个作为有效撤销表空间的表空间,且该表空间必须已被创建为一个撤销表空间,同时其内部的所有撤销段都会被自动联机即,使撤销段可用;
UNDO_RETENTION:以秒为单位进行设置的可选参数。该参数指定了保留过期撤销数据的时间,以保证数据库不出现ORA-1555错误。如果没有设置这个参数或将其设置为0,则ORACLE仍会尽可能长时间地保留撤销数据。UNDO_RETENTION参数的最大值总与撤销表空间的大小一致。
如果配置了保证撤销保留(见后),则UNDO_RETENTION参数就不是可选的。针对撤销的默认操作模式是:对于事务与查询来说,ORACLE更倾向于维护事务。如果在查询可能出现ORA-1555失败与事务必定出现ORA-30036失败之间选择撤销表空间的大小,则ORACLE会通过重写查询所需的已提交撤销数据使指定事务继续进行。UNDO_RETENTION是 ORACLE试图达到的唯一目标。
ORACLE10G版本中存在保证撤销保留的选项。经过UNDO_RETENTION参数所设定的时间之前,撤销数据决不会被重写。在表空间层次上通过Retention Guarantee子句就能够启用撤销保留保证。可以在创建撤销表空间或修改撤销表空间时启用该特性。一旦激活某个已被指定保留保证的撤销表空间,如果所有查询都能够在撤销保留时间内结束,则这些查询都将成功完成,而且也不会再次接收到快照过旧的错误。由于ORACLE在经过保留时间前不会重写已提交的撤销数据,故不利的方面是事务可能由于缺乏撤销表空间而导致失败。我们可以通过SQL*PLUS中更改某个表空间的撤销保留保证,但无法通过EMDC来完成。
调整与监视撤销表空间
撤销表空间应该足够大,这样才能存储并发事务生成的所有撤销数据的最坏情况,这些数据是有效的撤销数据及长时间运行查询所需的过期撤销数据。在更高级的环境中,最好还应该添加允许闪回查询的空间。算法是:首先计算在最高工作负荷时生成撤销的速度,然后再乘以最长的查询的时间长度。
查询V$UNDOSTAT视图可以得到需要知道的所有信息。
删除与缩小撤销段
创建一个撤销表空间时,ORACLE会在这个表空间内创建一个撤销段池。如果并发事务数超过了这个池中的撤销段数,则ORACLE会创建更多的撤销段。如果某个事务的撤销数据超过了其撤销段的大小,则这个撤销段也会被扩展。在正常运行期间,如果撤销表空间受到与空间相关的压力,则ORACLE就会在必要时自动将过期撤销数据的区间从一个撤销段转移至另一个撤销段,从而确保撤销段的空间足够保存当前运行事务所产生的有效撤销数据。用于重新分配撤销表大小甚至删除撤销表的额外机制由SMON驱动。每隔24小时,SMON进程都会查看撤销表空间,并且删除用于满足最高工作负荷要求但已不再需要的撤销段,则时还会缩小过大的撤销段。
如果撤销段被填满,则这个撤销段的大小会根据这个事务的撤销数据量按需要增加;
执行一条DML语句时磁盘上的数据与撤销块都会被更新,并且相应的变化会被写至日志缓冲区;
即使使用了自动的撤销管理段,但仍遇到快照过旧错误,则应该首先调整查询,再加撤销表空间,启用撤销保留保证。
针对一连串SET transaction read only设置要求广泛地使用撤销数据,故会导致快照过旧错误。
十七、处理锁定
借助于记录和表锁定机制,可以实现并行访问的串行化。ORACLE中,锁定是完全自动的。
共享锁和排他锁:在指定记录上请求排他锁的第一个会话将得到这个锁定,其他请求对该记录进行写访问的会话则必须等待。即每次只能有一个会话可以获得排他锁。指定记录上的排他锁只有在COMMIT或ROLLBACK后才会被解除。共享表被设置于整个表上,多个会话可以获得同一个表上的共享锁。设置共享所的目的是为了防止另一会话获得这个表上的排他锁。在表上放置排他锁时需要执行DDL语句。执行DML语句,当前会话必须获取待更改记录上的排他锁及包含这些记录表上的共享锁。
DML语句至少需要受影响记录上的排他锁及包含这些记录表上的共享锁。排他锁能够防止其他会话干预指定记录,共享锁则能阻止其他会话使用DDL语句修改表的定义。这两种锁定会被自动请求。如果某DML语句在指定记录上无法获得所需的排他锁,则该语句将被挂起直至获得所需的排他锁。
DDL语句需要使用所涉及对象上的排他锁。只有在针对指定表的所有DML事务结束,且记录上的排他锁及表上的共享锁都被解除后,才能获得执行DDL命令所需的排他锁。任何DDL语句所需的排他锁都是自动请求的,但如果无法获取需要的排他锁,则DDL语句会立即终止。
请求锁定需要排队。如果不希望某个会话在无法获取锁定时进行排队,唯一的方法就是使用SELECT FOR UPDATE命令的WAIT或NOWAIT子句。由于SELECT不需要任何锁定故普通的SELECT语句总是能够成功的执行,但DML语句会挂起。SELECT FOR UPDATE命令采用专有的模式来选择和锁定记录。如果某条记录被锁定,则在锁定释放之前,SELECT FOR UPDATE语句就会像DML一样进行排队并挂起会话。使用SELECT FOR UPDATE NOWAIT和SELECT FOR UPDATE WAIT n就可以避免挂起会话,n是以秒为单位的数值。使用SELECT FOR UPDATE的任一子句获得锁定后,就可以在不必挂起的情况下执行DML命令。如果使用NOWAIT子句则会在无法获得锁定的情况下立即终止语句。使用WAIT n子句会在无法获得锁定的情况下等待n秒,如果n秒后还无法获得锁定则立即终止语句。
锁定争用机制:当某个会话请求一条记录或一个对象上的锁定时,由于其他会话已经获取了该记录或对象上的排他锁而无法获取锁定时,这个会话将挂起,这种现象称为锁定争用。死锁是锁定争用的一种特殊情况,通常由数据库本身自动解决。
SET TRANSACTION READ ONLY语句能够保证在不带来任何锁定的前提下,该会话不会看到任何表上被提交或未被提交的任何DML语句,直至使用COMMIT或ROLLBACK命令终止这个只读事务。
在紧急情况下,DBA能够通过终止长时间拥有过多锁定的会话来解决锁定争用的问题。强制终止某个会话时,该会话拥有的任何锁定都会在回滚其作用的事务时同时被释放。此时被锁定的会话将被释放并继续执行。可以通过EMDC功ALTER SYSTEM KILL SESSION 'session_id,session serial Number'来终止指定会话。
死锁不是DBA的问题并且数据库自身能够自动解决死锁。与死锁相关的信息会被写入告警日志,并且被详细记录至某个跟踪文件。除了报告死锁的发生之外,DBA不需要完成针对死锁的操作。死锁问题由ORACLE数据库自动解决的。死锁是一种程序设计错误。告警日志位于BACKGROUND_DUMP_DEST实例参数指定的目录内,并且名为alert_<instance_name>.log。告警日志最后一个条目会告诉跟踪文件的位置。跟踪文件位于USER_DUMP_DEST实例参数指定的目录内。ORACLE会通过回滚导致死锁的某条语句来解决死锁问题。
锁定是由排队机制实现的,队列跟踪了已被请求的锁定,并且队列中的锁定排列顺序与锁定被请求的顺序一致。在等待排队时,会话将被挂起。针对表和记录的锁定是完全自动的。
十八、配置数据库的备份与恢复
重做与撤销机制都能保证数据库绝对不会出现讹误。
服务级别与备份和恢复相关的三个方面:MTBF(mean time between failures,平均失败时间),MTTR(mean time to recover,平均恢复时间)和数据损失量。DBA的目标就是减少MTTR和数据损失量的同时增加MTBF。MTBF是指数据库出现失败的频繁度。ORACLE提供了两种有助于百分之百可用性的高级选项:RAC和Streams。RAC数据库由位于多台计算机上的多个实例所打开的一个物理数据库组成。RAC使硬件,操作系统与软件免遭失败。Streams环境由位于不同计算机上的两个或多个数据库组成。Streams能够根据需要保持两个数据库实时同步。Streams选项使磁盘和网络免遭失败及硬件,操作系统与软件免遭失败,与RAC相比,其容错能力更强。MTTR是指数据库出现失败后的停机时间。Data Guard实现使数据库在任何情况下都不会损失数据。在Data Guard系统中,实际运行的数据库(被称为主数据库)受到一个或多个备用数据库的保护。RAC、Streams和Data Guard选项都不会对性能造成影响。任何容错系统都特别依赖于硬件冗余。DBA需要与系统管理员一起实现容错功能。
廿一、管理ORACLE数据库中的全球化特性
ORACLE的默认字符集为7比特的ASCII或7比特的EBCDIC。Unicode标准是一种用于字符编码的国际标准,并且包含了任何计算机系统需要的所有字符。目前,ASCII代码(American Standard Code for Information Interchange,美国信息交换标准代码),EBCDIC(Extended Binary Coded Decimal Interchange Code,扩充的二进制编码的十进制交换码),ISO(International Standards Organization,国际标准化组织),ANSI(American National Standards Institute,美国国家标准化组织)。AL16UTF16:一种两字节的Unicode字符集,并且是ORACLE10g唯一支持的固定长度的Unicode字符集。可以通过查询V$NLS_VAILD_VALUES视图取得NLS的相关信息。
地区支持:选中某个地区可以默认设置许多NLS特性。选择地区还可以默认设置日期和周的编号,收支符号,日期格式,小数点分隔符与组分隔符及货币符号。
指定全球化级别(由低到高的优先级顺序):
数据库,实例,客户机环境,会话,语句。在服务器端,实例设置优先于数据库设置,但是在服务器上的所有相关设置都会被客户端重写。
在创建数据库阶段必须正确完成的两个设置:DB_BLOCK_SIZE,该参数被用来指定SYSTEM表空间的块大小。如果没有重建数据库,就无法修改这个参数;数据库字符集,被用于存储VARCHAR2,CLOB,CHAR和LONG数据类型的所有数据。如果改变了字符集,可能销毁这些数据类型中已有的所有数据。
从9i开始,能够作为National Character Set被支持的两种Unicode字符集是AL16UTF16和UTF8。AL16UTF16是一个定长的两字节字符集,UTF8是一个长度可变的字符集。在两种字符集之间进行选择时,需要考虑与NVARCHAR2和NCLOB列中预计存储数据类型相关的空间效率及性能。要使用支持多种语言的数据库,可以使用Unicode字符集作为实际的数据库字符集,此时所支持的选项为UTF8和AL32UTF8,这两种字符集都是长度可变的多字节字符集。数据库字符集的唯一限制是必须将US7ASCII或EBCDIC作为一个子集,原因在于数据库字符集被用于存储SQL或PL/SQL源代码,而这些源代码采用上述类型字符编写的。默认的数据库字符集与National Character Set为US7ASCII与AL16UTF16。如果数据库是DBCA创建的,则DBCA会提供一个默认的数据库字符集,这个字符集与运行DBCA的操作系统的字符集相同。
改变数据库字符集:从9i开发虽然存在改变数据库字符集的方法,但是无法保证这种方法有效。DBA应当全面负责检查数据库字符集的改变不会损坏数据。ORACLE提供了下列两种有助于决定字符集修改的工具:数据库字符集扫描程序(Database Character Set Scanner)和语言与字符集文件扫描程序(Language and Character Set File Scanner)。在UNIX下分别为csscan和lcsscan,在WINDOWS下为csscan.exe和lcsscan.exe。为了使数据库能够运行数据库字符集扫描程序,必须首先运行csminst.sql脚本。语言与字符集文件扫描程序能够尝试标识用于文本文件的语言和字符集。判断能够无损地改变数据库字符集后,可以通过执行ALTER DATABASE CHARACTER SET命令来完成字符集的修改。改变National Character Set的等价命令为ALTER DATABASE NATIONAL CHARACTER SET。这条命令的唯一限制是目标字符集必须是原始字符集的一个超集,但是并不能保证不存在讹误。保证不出现讹误应当是DBA的责任。
数据库内的全球化:通过查看NLS_DATABASE_PARAMETERS视图可以查看NLS设置。
实例级别的全球化:在RAC环境中,不同的实例可以具有不同的设置。全球化实例参数是静态参数,在变化之前必须重启实例。NLS_INSTANCE_PARMAETERS视图给出了当前有效的设置,除与不应用于实例的字符集和RDBMS版本有关的3条记录外,该视图与NLS_DATABASE_PARAMETERS视图具有相同的记录;
客户端环境设置:NLS_LANG环境变量的3个元素:语言,地区和字符集都是可选的。NLS_LANG是一个关键的变量,其完整规范包括语言,地区和字符集。服务器与客户端全球化设置之间的转换由ORACLE NET完成,所有必要转换都是由ORACLE NET的双任务公共层实现的。
会话级别的全球化设置:ALTER SESSION命令来建立自己的全球化首选项。DBMS_SESSION程序包可以代替ALTER SESSION命令。会话级别的规范优先于服务器端数据库与实例级别的设置,而且还会重写用户使用环境变量配置其会话的各种尝试。V$NLS_PARAMETERS视图中显示了当前作用于会话的全球化设置。除字符集外,NLS_SESSION_PARAMETERS视图中也显示了相同的记录。
语句级别的全球化设置:是最优控制级别的全球化设置。
语言排序与选择:ORACLE默认使用二进制排序。
Locale Builder工具的使用:UNIX环境下:$ORACLE_HOME/nls/lbuilder/lbuilder,WINDOWS环境下:%ORACLE_HOME%/nls/lbuilder/lbuilder.bat。
时区:ORACLE环境能够知道所使用的时区。为了使用时区,需要指定数据库所动作的时区及使用TIMESTAMP WITH TIME ZONE与TIMESTAMP WITH LOCAL TIME_ZONE数据类型。前一种类型在被存储时不会被格式化至数据库时区,不过将具有一个时区指示标志,这个标志说明其引用的时区。后一种数据类型在被存储时会被格式化至数据库时区,随后在检索时被转换至客户机时区。普通的DATE和TIMESTAMP数据类型在被存储时始终会被格式化至数据库时区,并且在选中时被原样显示。可以使用CREATE DATABASE命令在创建数据库时设置时区,也可以在之后通过ALTER DATABASE SET TIME_ZONE=命令进行调整。如果没有进行设置,就会在创建数据库时将数据库时区默认为主机操作系统的时区。客户机时区默认为客户机操作系统的时区。使用ORA_STDZ环境变量也可以设置客户机时区。在会话内,使用ALTER SESSION SET TIME_ZONE也可以设置时区。使用完整的名字,简写的名字与格林威治标准时间的小时和分钟的固定偏移量都可以指定时区。指定偏移量的方法无法根据夏令时或冬令时进行相应的调整。V$TIMEZONE_NAMES视图中显示了被支持的所有时区。
全球化设置会影响消息的语言,排序顺序,日期格式,历法,日期和月份的名字或数值格式等。字符集的选择至关重要,并且涉及两上字符集的选择。数据库字符集被用于VARCHAR2,CLOB,CHAR和LONG列;National Character Set则用于NVARCHAR2,NCLOB和NCHAR列。
NLS_DATE_LANGUAGE与NLS_SORT由NLS_LANGUAGE控制的两个参数,NLS_DATE_FORMAT与NLS_NUMERIC_CHARACTERS参数由NLS_TERRITORY控制。
Character Set Scanner工具会报告改变字符集所导致的问题。视图V$NLS_VAILD_VALUES视图可以说明能够被支持的语言。