模式是一组DB对象的集合,模式被用户所有且和用户同名。模式对象是用户建立的逻辑结构,某些对象含有数据,比如表和索引;某些只含有定义,比如视图。需要注意的是,模式和表空间没有联系。同一个模式的对象可以使用不同的表空间;同一个表空间可以包含不同模式的数据。
模式对象的名称在同一个模式中必须是唯一的,在不同的模式中可以相同。当建立一个对象是,必须要保证是处在合适的模式中,一个简单的方法就是使用对应的用户登录DB,并创建对象。一般来说,某个应用拥有的所有对象都要放到同一个模式中。
模式对象权限
如果用户被授予了DBA角色,它就可以增删改所有对象,无论是在自己的模式还是其他模式,比如SYS和SYSTEM用户。当然有更安全的方法,可以授予RESOURCE角色给用户,然后可以在其所有的模式中增删改模式对象。
另外,只有DBA可以登录并使用EMDC,比如SYS和SYSTEM用户,非管理员用户不能访问EM。如果其他用户需要登录EM的话,需要授予他们SELECT_CATALOG_ROLE角色,否则他们就只能使用SQLPlus接口。
表
表是Oracle数据库内数据存储的基本单位。数据是按照行和列来存储。你用一个表名(比如employees)、一系列列来定义表。你为每列指定一个列名(比如employee_id,last_name和job_id等),一个数据类型(比如VARCHAR2,DATE,NUMBER)和一个宽度。宽度可以是数据类型(比如日期)预先定义好的。如果列是NUMBER类型,定义范围和精度就可以了。行是关联到一个记录的列信息的集合。
你可以指定表中每个列的规则。这些规则叫做完整性约束条件。NOT NULL就是一个完整性约束的例子。这个约束条件要求这列的每一行都要包含一个值。
你还可以指定表列在保存在数据文件之前将数据加密。加密阻止了越过数据库访问控制来直接使用操作系统工具查看数据文件的现象。
在你创建表之后,使用SQL语句插入行数据。表的数据就可以使用SQL查询、删除和更新。
表数据如何保存
当你创建表时,Oracle在一个表空间上自动分配一个数据段来保存表将来的数据。你有两种方式可以控制一个表数据段的分配和使用:
1 你可以通过设定数据段的存储参数来控制分配给数据段的空间大小
2 通过设置组成数据段的区段的数据块的参数PCTFREE和PCTUSED来控制块的空闲空间的使用。
对于聚集表来说,Oracle在针对聚集表创建的数据段上保存数据,而不是在表空间的上分配数据段保存数据。聚集表创建和修改时不能指定存储参数。聚集的存储参数设置控制了聚集中中所有表的存储。
表的数据段(或者聚集数据段,针对聚集表)可以创建在表拥有者的默认表空间上,或者在CREATE TABLE语句中指定。
行格式和大小
Oracle将一个包含至多256列的数据库行保存在一个或多个行片中。如果整个行能够插入一个数据块中,然后Oracle会保存这个行在一个行片中。虽然如此,如果所有的行数据不能插入一个数据块或者对一个现存行的更新造成行数据超出了它的数据块,然后Oracle会使用多个行片保存行。一个数据块通常一行只包含在一个行片中。当Oracle必须在多个行片中保存行时,它就是跨块链接的(行链接)。
当一个表拥有多余255个列,255之后的列的数据就会在同一块中链接(如果不超出块的话)。这个叫做块内部链接。行片链接是通过片的ROWID来链接起来的。通过块内部链接,用户可以从同一块中得到所有数据。如果行可以放在一个块中,用户不会感觉到I/O性能的影响,因为取得额外的行(255之后的行)不需要额外的I/O操作。每个行片,无论链接还不是没有链接,都包含一个行首部(row header)和部分或全部行数据。单独的行可能跨越行片或者数据块。下图是行片的格式
分区表
分区表允许你将你的数据分成更小的容易的管理的叫做分区的部分,甚至还可以包含子分区。索引可以按照类似的方式分区。每个分区可以单独管理,可以独立于其他分区进行操作,这样就针对可用性和性能方面提供了更好的调整结构。
嵌套表
你可以创建一个表,表中的列类型是另外一个表。就是说,表可以嵌套在另一个表中作为一个列的值。Oracle数据库服务器并不是把嵌套表保存在父表的行里,而是将一个存储表和嵌套表行关联。父表行包含一个唯一标识符来关联嵌套表实例。
临时表
除了持久表,Oracle还可以创建临时表来保存会话私有的数据,这些数据只在事务或会话期间保存。CREATE GLOBAL TEMPORARY TABLE语句可以创建一个事务型或会话型临时表。对于事务型临时表,在事务持续期内数据存在。对于会话型临时表,会话持续期间数据存在。临时表中的数据是会话独立的。每个会话只能看到和修改自己的数据。DML锁不能加到临时表的数据上。LOCK语句对临时表的数据没有影响,因为每个会话拥有它们的私有数据。
会话型临时表的TRUNCATE语句删除当前临时表的数据。不能删除其他会话中使用同一个表的数据。临时表上的DML语句产生的数据改变不会产生重做日志。但是会产生数据的undo日志和undo日志的重做日志。会话结束时临时表的数据会自动删除,包括用户登出或者会话意外终止(比如会话或实例失败)。你可以使用CREATE INDEX语句来为临时表创建索引。临时表上的索引也是临时的,临时表上的索引数据也和临时表的数据一样在事务或者会话期间存在。你还可以创建同时访问临时表和持久表的视图。你还可以创建临时表的触发器。Oracle工具可以导入导出临时表的定义。但是,即使你使用ROWS子句也无法导出任何数据行。类似的,你可以复制历史表的定义,但是无法复制其数据。
外部表
外部表访问外表资源的数据就如同它们是数据库中的表一样。你可以连接目标数据库并使用DDL(数据定义语言)创建元数据外部表。外部表的DDL由两个部分组成:一部分描述了Oracle列类型,另一部分(访问参数)描述了外部数据到Oracle数据列的映射。一个外部表不用于任何保存在数据库内部的数据。也不描述数据如何保存在外部资源中。相反,它描述了外部表层如何展现数据给服务器。外部表只是一个数据文件上的数据需要的访问驱动和外部表层的必要的转换,这样数据才能符合外部表定义。外部表是只读的;因此不允许任何DML操作,不能创建任何索引。
视图
视图是一个或多个表或者其他视图的数据的定制展示。一个视图将查询的输出作为一个表。因而,一个视图可以被认为是一个存储的查询或虚拟表。你可以在大部分可以使用表的地方使用视图。例如,employees表拥有几个列和一些行的信息。如果你想只使用其他的5列或者指定的行,然后你就创建这张表的视图,这样其他用户就可以直接访问。
因为视图来源于表,所以它们之间有类似的地方。例如,你可以像表一样定义1000个列的视图。你可以查询视图,在某些限制下还可以更新、插入和删除视图中的数据。视图上执行的操作实际上影响的是视图基表的数据,并且服从基表的完整性约束条件和触发器。你不能直接在视图上显示定义触发器,但你可以在视图引用的基表上定义。Oracle还支持视图上的逻辑约束。
许多重要的视图在SYS模式,有两种,静态数据字典视图和动态性能视图。
静态数据字典视图
之所以被称为静态视图是因为他们改动不频繁,只有当数据字典被改动时,例如创建新表或者赋予权限时,数据字典被改动。许多数据字典表拥有以下三种对应的视图:
1. DBA_ 视图:为了管理员使用,显示DB所有相关信息。例如DBA_TABLESPACES,为了每个表空间显示一行信息。
2. ALL_ 视图:显示所有当前用户可以访问的信息,无论是否在用户所有的模式中,例如ALL_TABLES。
3. USER_ 视图:显示当前用户模式中的所有信息,查询这个视图无需特殊权限。例如USER_TABLES。
动态性能视图
监控当前DB活动,仅管理员可以查询,其名称以"V$"开头。例如视图V$SGA,其返回SGA的大小。
视图如何存储
和表不同,视图并不分配存储空间,也不包含实际数据。相反,视图是一个查询的定义,是从视图引用的表中抽取数据的查询。这些表叫做基表(base table)。基表可以是表、也可以是视图(或者实体化视图)。因为视图基于其他对象,视图只需要在数据字典中存储视图的定义(存储的查询),而不需要其他的存储。
视图的机制
Oracle将定义视图的查询的文本保存在数据字典中。当你在SQL语句中引用视图时,Oracle:
1、将引用视图定义的查询合并到语句中
2、在一个SQL共享区域解析合并的语句
3、执行语句
只有在共享SQL区域中不包含类似的语句,Oracle会在新的共享SQL区域中执行引用视图的语句。因而当你使用视图时,你通过共享SQL(视图的SQL)可以降低内存消耗。
视图参数支持国际化
当Oracle评估包含国际化支持的参数(如TO_CHAR,TO_DATE和TO_NUMBER)文字字符或者SQL函数时,Oracle使用会话默认支持的国际化参数。你可以通过在视图定义中指定国际化支持的参数来覆盖默认值。
索引
索引是表和聚集表可选的关联结构。你可以在表的一个或多个列上创建索引来加快其上的SQL语句执行速度。就如同使用本手册的索引比没有索引可以帮你快速定位信息一样,一个Oracle索引提供了对于表数据更快的访问方法。正常情况下,索引是降低磁盘I/O的主要方法。你可以在表上创建很多索引,可以使用列的任意不同组合来创建索引。你可以在相同的行上创建多个索引,只要列的组合顺序不同就可以了。例如,下列语句指定了有效的组合:
CREATE INDEX employees_idx1 ON employees (last_name, job_id);
CREATE INDEX employees_idx2 ON employees (job_id, last_name);
Oracle提供了多个索引模式,提供了针对不同情况下的性能优化:
u B树索引
u B树聚集索引
u Hash聚集索引
u 反向键值索引
u 位图索引
u 位图联结索引
Oracle还支持函数索引和指定应用程序或使用范围的域索引。
增加或者减少索引并不需要修改任何的SQL语句的语法。索引只是数据的快速访问途径。它只影响执行速度。假定一个数据被索引,索引就会直接指向包含这个值的行的位置。索引在逻辑上和物理上都和关联表的数据独立。你可以任何时候创建和删除索引而不会影响基表以及其他的索引。如果你删除索引,所有的应用程序可以继续运行。但是,以前访问删除的索引的数据会降低速度。
索引是一个独立的结构,还是需要存储空间的。索引创建后Oracle自动维护和使用索引。不需要用户额外操作,Oracle会自动将数据改变(比如增加行、修改行或删除行)反映到相关索引上。索引数据的获取性能基本保持一致,甚至增加了新行也是如此。但是一个表上存在多个索引还是会降低更新、删除和插入的性能,因为Oracle必须更新表的相关索引。优化器可以使用现存的索引来构建另一个索引。这样会创建一个更快的索引。
唯一和非唯一索引
索引可以是唯一或者非唯一的。唯一索引保证表在索引列(一个或多个)没有重复的行值。非唯一索引并不强迫限制列值(唯一)。Oracle推荐显示的使用CREATE UNIQUE INDEX语句来创建唯一索引。通过主键或唯一约束来创建唯一索引并不一定会创建新索引,而且创建的索引也不确保是唯一索引。
复合索引
复合索引(也叫关联索引)是一个在一个表的多个列上创建的索引。复合索引的列可以是任何顺序的,并且不需要在表中相邻。在SELECT语句的WHERE子句引用了复合索引的全部或者起始列的情况下,复合索引可以加快获取数据的速度。因而,定义中使用的列的顺序非常重要。通常,最常访问或最高选择率的行放在前面。通常一个复合索引不能超过32个列。对于位图索引来说,列数最大数目为30。一个键值大致不能超过一个数据块的可用空间的一半(多个限制的最小值)。
索引和键
虽然这个两个概念经常可以互换,但索引和键还是有区别的。索引是保存在数据库中的物理存储的结构,用户可以使用SQL语句创建、修改和删除索引。创建索引是为了提供一种的更快的访问表数据的方式。键严格来说是一种逻辑概念。键对应于Oracle叫做完整性约束的这个特性,这个约束在数据库中强制了商业规则。因为Oracle使用索引来强制一些完整性约束,键和索引经常互换的使用。但是,不要对它们彼此产生混淆。
索引和NULL
索引中的NULL值一般认为是不同的,除非索引中的2个或者更多的非NULL值行是一样的,这种情况下,这些行被认为是相等的。因而UNIQUE索引不允许重复值,所以索引不包含NULL值(即NULl值不索引)。如果整个行全为空,索引不会起作用。Oracle不对所有键值为NULL的列索引,除非是在位图索引或聚集键列值为NULL的情况下。
函数索引
你可以针对包含表中一个或多个列的函数和表达式建立索引。一个函数索引计算函数或表达式的值并保存在索引中。你可以创建B树函数索引,也可以创建位图函数索引。构建索引的函数可以是数学表达式,也可以包含PL/SQL函数、包函数、C标注、SQL函数。表达式不能包含任何聚集函数,并且必须是有确定值的。对在需要构建索引的行包含的对象类型,函数可以是该类型的一个方法,比如映射方法。但是,你不能在LOB、REF或嵌套表列构建函数索引,而且如果对象类型包含LOB、REF或嵌套表的话,也不能构建函数索引。
索引如何存储
当你创建一个索引时,Oracle在表空间上自动分配一个索引段来保存索引数据。你可以使用下列方式控制索引段的空间分配和备用空间的使用:
1 设置索引段的存储参数来控制索引段的区段的分配
2 设置索引段的PCTFREE参数来控制组成索引段的区段的数据块的空闲空间
索引段的表空间可以是拥有者的默认表空间或者CREATE INDEX语句指定名字的表空间。你不必将索引放在和关联表相同的表空间中。此外,你可以通过将索引和表放在位于不同磁盘驱动器的不同表空间上可以提高使用索引的查询速度,因为Oracle可以并发的获取索引和表的数据。
索引块的格式
索引数据的可用空间是Oracle块大小减去块首部、条目首部、rowid、和每个索引值的一个长度字节。当你创建索引时,Oracle将索引列取出和排序,并把每一行的索引值和rowid一起保存。然后Oracle从下往上装载索引。例如,考虑如下语句:
CREATE INDEX employees_last_name ON employees(last_name);
Oracle将employees表根据last_name排序。然后按照排序顺序来装载last_name和对应的rowid值到索引上。当它使用这个索引时,Oracle对排序的last_name值快速扫描,然后使用查询到的last_name值关联的rowid值来定位行。
索引的内部结构
Oracle使用B树索引来加快数据访问。没有索引的情况下,你不得不依次扫描数据来找到值。对于n行来说,平均的查询行数为n/2。这个不会随着数据量的增加而缩放。考虑将一个值的排序列表分成多个块宽度的范围(页块)上。块的末尾除了块的指针之外都可以保存在一个搜索树中,n条数据花费log(n)的时间就可以找到。这就是Oracle索引隐含的基本原理。
B树结构的优势
> 树的所有页块高度相同,所以获取索引上任何地方的任何数据所需的时间大致相同
> B树索引自动保持均衡状态
> B树索引的所有块平均来说是3/4满的
> B树对大多数查询提供了优秀的检索性能,包括精确识别和范围搜索
> 插入、更新和删除都是高效的,并维护键顺序以便快速的获取数据
> B树索引对于小表和大表同样优秀,并且不会随着表尺寸的增长而降低性能
性能和存储考虑
键要所会节省大量的空间,让你可以在每个索引块上保存更多的键,这样会导致更少的I/O和更好的性能。
虽然键压缩减少了索引需要的存储空间,它却提高了在索引扫描时重构键值时需要的CPU时间。它还会导致额外的空间消耗,因为每个前缀条目对应有4个字节的消耗。
维度
一个维度定义多列或列集合的继承关系(父/子)。子级别的每个值和父级别有且只有一个值关联。继承关系是从继承的一个级别到继承的下一个级别的函数依赖。维度是列之间的逻辑关系的容器,而且它不需要分配任何数据存储空间。
CREATE DIMENSION语句指定:
> 多个LEVEL子句,每个代表维度中的一列或列集合
> 一个或多个HIERARCHY子句代表临近级别的父子关系
> 可选ATTRIBUTE子句,每个代表单独级别的关联列或列集合
维度中的列来自于同一个表(非规泛化的)或者来自于多个表(完全或部分规泛化)。在多个表上的多个列上定义维度,使用HIERARCHY子句的JOIN子句来连接数据库。
聚集
聚集是一种可选的保存表数据的方法。聚集是一组共享数据块的表,这些表共享公用的行并经常一起使用。例如,employees和departments表共享了department_id列。当你聚集employees和departments表时,Oracle物理上将employees和departments表的共用department的所有行保存在相同的数据块上。