表与表簇概述

来源:互联网 发布:古兰经教学软件 编辑:程序博客网 时间:2024/06/11 07:10

表是 Oracle 数据库中的数据组织的基本单位。 一个表描述了一个实体,其相关重要信息必须被记录。

Oracle 数据库表分为以下几个基本类别:
关系表

关系表具有简单的列,是最常见的表类型。

对象表

列对应于对象类型的顶层属性。

您可以创建一个具有下列组织特征的关系表:

堆组织表,它不会以任何特定顺序存储行。 默认情况下,CREATE TABLE 语句创建堆组织表。

索引组织表,它按主键值对行进行排序。 对于某些应用程序,索引组织表可以增强性能更有效地使用的磁盘空间

外部表,是一个只读表,它的元数据存储在数据库中,但其数据存储在数据库外。

表要么是永久的,要么是临时的。 永久表的定义和数据保持跨会话存在。 临时表的定义与永久表有相同的存在方式,但其数据仅在一个事务或会话的持续期间有效。临时表可用于暂存某些应用程序在运行过程中由多个操作所生成的中间结果集

列和行

表的定义包括表名称和列集。 列标识由表所描述的实体的一个属性。

一般地,当您将创建一个表时,给每列一个列名称、 数据类型、和宽度。与DATE类型一样,宽度可以由数据类型预先确定。

表可以包含虚拟的列,与非虚拟列不一样,虚拟列不占用磁盘空间。 数据库通过计算一组用户指定的表达式或函数,按需派生出虚拟的列值。

创建一个表后,可以使用 SQL插入、 查询、 删除、和更新行。 行是对应于表中某条记录的列信息的集合。

Oracle数据类型

每个列都有一种数据类型,这与特定的存储格式、限制、和有效的值范围相关联。 一个值的数据类型与一组固定的属性相关联。 这些属性会使Oracle数据库区别对待不同数据类型的值。例如,你可以把NUMBER 数据类型的值相乘,但不能把RAW数据类型的值相乘。

在创建表时,您必须为每个列指定数据类型。 随后在该列中插入的每个值都假定为该列的数据类型

Oracle 数据库提供了几种内建的数据类型。 最常用的数据类型分为以下几类:

 字符数据类型
 数字数据类型
 日期时间数据类型
 ROWID数据类型
格式模型和数据类型(Format Models and Data Types)

其他几种重要的内建类型包括RAW、大对象 (LOB)、 和集合。 PL/SQL 具有用于常量和变量的数据类型,包括布尔、 引用类型(reference types)、 复合类型 (记录) 、和用户定义类型。

字符数据类型

字符数据类型将字符(字母数字)数据存储在字符串中。。 最常用的字符数据类型是 VARCHAR2,它是用于存储字符数据的最有效的选项

与字符编码模式相对应的字节值,一般称为字符集或代码页。 数据库字符集是在数据库创建时建立的。字符集的例子有7 位 ASCII码、 EBCDIC码、和 Unicode utf-8。

字符数据类型的长度语义可以以字节或字符为单位。 字节语义将字符串视为一个字节序列。 这是字符数据类型的默认值。 字符语义将字符串视为字符序列。 字符在技术上是数据库字符集的代码点

VARCHAR2和CHAR数据类型

VARCHAR2 数据类型存储变长字符文本。文本和常量值这两个术语是同义词,指的是一个固定的数据值。字符文本包括在单引号中,以便数据库可以将它们与模式对象名称区分开来。

当创建一个有 VARCHAR2 列的表时,指定该列的最大字符串长度。

对每一行, Oracle数据库将按可变长度字段来存储值,如果一个值超出最大长度,数据库将返回一个错误。使用 VARCHAR2 可以减少空间占用。

与VARCHAR2不同, CHAR 存储固定长度的字符串。当创建一个有 CHAR 列的表时,需要为该列指定一个字符串长度。默认值是 1 个字节。数据库使用空格填充到指定的长度的值

Oracle 数据库将使用非填充比较语义来比较 VARCHAR2 值,而使用空白填充比较语义来比较 CHAR 值。(注:这里的空白填充是指右填充。)

NCHAR与NVARCHAR2数据类型

NVARCHAR2 和 NCHAR 数据类型存储 Unicode 字符数据。*Unicode 是一种通用的编码字符集,可以将任何语言的信息存储在一种字符集中。NCHAR 存储对应于国家字符集*的固定长度字符串,而 NVARCHAR2 存储可变长度的字符串。

当您创建数据库时,指定国家字符集。NCHAR 和 NVARCHAR2 数据类型的字符集必须是 AL16UTF16 或 UTF8。这两种字符集都使用 Unicode 编码。

当您创建一个有NCHAR 或 NVARCHAR2 列的表时,其最大大小始终是字符长度语义。对于NCHAR 或 NVARCHAR2,字符长度语义是默认的,也是唯一的长度语义。

注:关于CHAR、VARCHAR2 与 NCHAR、NVARCHAR2:

CHAR、VARCHAR2默认是字节长度语义,也可以是字符长度语义。
NCHAR、NVARCHAR2默认是字符长度语义,而且是唯一的长度语义。所以我们可以这样来创建表:

create table test (col1 char(2 byte), col2 char(2 char), col3 nchar(2));SQL> desc test Name                      Null?    Type ----------------------------------------- -------- ---------------------------- COL1                           CHAR(2) COL2                           CHAR(2 CHAR) COL3                           NCHAR(2)

关于字符长度语义的列可以存储的字节大小与数据库字符集有关。

数字数据类型

Oracle数据库的数字数据类型存储固定和浮点数字、零、或无穷。某些数值类型也可以存储未定义操作的结果值,叫做”非数字”或NAN。

Oracle 数据库以变长格式存储数字数据。用科学计数法存储值,其中一个字节用于存储指数。数据库使用最多 20 个字节存储尾数,即浮点数的有效位数部分。****Oracle 数据库不会存储前导零和结尾零

NUMBER数据类型

NUMBER 数据类型存储固定和浮点数字。数据库可以存储几乎任何规模的数字。此数据保证在运行Oracle数据库的不同操作系统之间可移植。大多数情况下,当您必须存储数值数据时,推荐使用 NUMBER 数据类型。

按NUMBER(p,s)的形式定义定点数,p 和 s 有以下特征:

精度

精度指定数字的总长度。如果不指定精度,则列按应用程序提供的数据存储值,不作任何舍入。

小数位数

小数位数指从十进制的小数点到最小有效数字的位数。正小数位数从小数点向右计数直至最小有效位。负小数位数从小数点向左计数直至(但不包括)最小有效数字。如果您指定了精度但没有指定小数位数,如NUMBER(6),那么小数位数为 0。

浮点数

Oracle 数据库为浮点数提供了两种互斥的数值数据类型: BINARY_FLOAT 和 BINARY_DOUBLE。这两种类型支持所有 NUMBER 数据类型提供的基本功能。然而,相比NUMBER使用十进制精度,BINARY_FLOAT 和 BINARY_DOUBLE 使用二进制精度,可以使算术计算更快并且通常可以降低存储需求。

BINARY_FLOAT 和 BINARY_DOUBLE 是近似数字数据类型。它们存储十进制的值的近似表示,而不是精确的表示形式。例如值0.1不能用BINARY_DOUBLE 或 BINARY_FLOAT完全精确地表示。他们经常用于科学计算。其行为类似于 Java 或XMLSchema中的FLOAT和DOUBLE数据类型。

日期时间数据类型

日期时间数据类型包括DATE和 TIMESTAMP。Oracle 数据库为时间戳提供全面的时区支持。

DATE数据类型

DATE 数据类型存储日期和时间。尽管日期时间可以用字符或数字数据类型表示,DATE具有特殊的相关属性。

数据库在内部将日期存储为数字。日期被存储为固定长度的域,共7 个字节,分别对应世纪、 年、 月、 日、 小时、分、和秒。

注意

日期完全支持算术操作,您可以像对数字一样,对日期进行加减操作。

数据库根据指定的格式模型显示日期。格式模型是一个描述在字符串中的日期时间格式的字符文字。标准的日期格式是DD-MON-RR,它会以01-JAN-09 的形式显示日期。

RR类似于 YY (年的最后两位),但返回值的世纪值会因指定的两位年份及本年度的最后两位不同而不同。假设在 1999 年,数据库显示为 01-JAN-09。如果日期格式使用 RR,那么09 指的是 2009,而如果格式使用 YY,那么 09 指的是1909。您可以更改实例或会话级别的默认日期格式。

Oracle 数据库以 24 小时制格式存储时间 — — HH:MI:SS。如果不输入的任何时间部分,那么默认情况下,日期字段中的时间是凌晨 00: 00: 00,如果只输入了时间,则日期部分默认为当月的第一天

TIMESTAMP 数据类型

TIMESTAMP 数据类型是日期数据类型的扩展。除了存储在 DATE 数据类型的信息,它同时还存储秒的小数部分。TIMESTAMP 数据类型对于存储精确时间的值很有用,比如那些必须跟踪事件顺序的应用程序。

DATETIME 数据类型TIMESTAMP WITH TIME ZONE和 TIMESTAMP WITH LOCAL TIME ZONE能感知时区。当用户中选择数据时,其值会被调整以适配用户会话的时区。此数据类型可用于收集和评估各地理区域的日期信息。

Rowid 数据类型

存储在数据库中的每一行都有一个地址。Oracle 数据库使用 ROWID 数据类型存储在数据库中的每一行的地址 (rowid)。Rowids 分为以下几类:

物理 rowids 存储堆组织表、 表簇、表分区、和索引分区中的行地址。

逻辑 rowids 存储索引组织表中的行地址。

外部 rowids 是外来表(如通过网关访问的DB2表)中的标识符。他们不是标准的Oralce数据库 rowids。

有一种数据类型称为通用rowid 或 UROWID,支持各种 rowids。

使用Rowid

Oracle 数据库在内部使用 rowids用于构造索引,最常见的 B 树索引,包含一个被划分成多个键范围的排序列表。每个键都与一个指向关联的行地址的 rowid 相关联,用于快速访问。最终用户和应用程序开发人员也可以使用rowids 的几个重要功能:

 Rowids 是访问特定行的最快方式。
Rowids 提供了查看表的组织方式的能力。
 Rowids 是给定表中的行的唯一标识符。

您也可以创建带 ROWID 数据类型列的表。例如,您可以定义一个异常表,其中一列为ROWID数据类型,以存储违反了完整性约束的行rowids。使用 ROWID 数据类型定义的列像其他表中的列一样, 其值可以更新,等等。

ROWID 伪列

Oracle 数据库中的每个表都有一个名为 ROWID 的 伪列。 伪列类似于表列,但实际上并不存储在表中。您可以从伪列中选择数据,但不能插入、 更新、或删除它们的值。伪列也类似于不带参数的 SQL 函数。不带参数的函数对于结果集中的每一行通常返回相同的值,而伪列通常为每个行返回不同的值。

ROWID 伪列的值是表示的每个行的地址的字符串这些字符串具有的数据类型 ROWID。在执行 SELECT 或 DESCRIBE列出表的结构时,此伪列并不显示,它也不占用空间。但是,每个行的 rowid 可以通过使用保留字 ROWID 作为列名的 SQL 查询来检索。

格式模型与数据类型

格式模型是一个字符文本,用来描述存储在一个字符串中的日期时间或数值数据的格式。格式模式不会更改数据库中的值的内部表示形式。

当您将一个字符串转换成日期或数字时,格式模型决定了数据库如何解释字符串。*在 SQL 中,你可以使用格式模型作为TO_CHAR 和 TO_DATE 函数的参数来格式化将从数据库中返回的一个值,或将存储到数据库中的一个值*。

完整性约束

完整性约束是一种命名规则,用于限制一个或多个表中的列值。这些规则可以防止向表中输入无效数据。此外,约束也可以防止当存在某些依赖项时删除表中的数据。

如果启用了约束,则输入或更新数据时,数据库会检查数据。不符合该约束的数据会被阻止输入。如果禁用了约束,则不符合该约束的数据可以被允许输入数据库。

您可以在创建表时或创建表后创建一个约束。如果需要,可以暂时禁用约束。数据库将约束存储在数据字典中。

对象表

Oracle 对象类型是具有名称、 属性、和方法的用户定义类型。*对象类型使得对现实世界中的实体(如客户和采购单等),作为对象在数据库中进行建模成为可能。*

对象类型定义逻辑结构,但不会创建存储。下面创建了一个名为 department_typ的对象类型。

CREATE TYPE department_typ AS OBJECT( d_name VARCHAR2(100),d_address VARCHAR2(200) );/

对象表是一种特殊的表,其中每一行表示一个对象。表的属性 (列) 派生自该对象类型的定义。

CREATE TABLE 语句创建一个名为 departments_obj_t 的对象表,其对象类型为 department_typ 。

CREATE TABLE departments_obj_t OF department_typ;INSERT INTO departments_obj_tVALUES ('hr', '10 Main St, Sometown, CA');

与关系表列相似,对象表只能包含同种类型的行,即具有同种声明类型的对象实例。默认情况下,对象表中的每个行对象都有一个相关联的逻辑对象标识符 (OID),以便在该对象表中唯一地标识该对象。对象表的 OID 列是一个隐藏列。

临时表

Oracle 数据库的临时表,用于存放只存在于某个事务或会话期间的数据。临时表中的数据是会话私有的,这意味着每个会话只可以查看和修改自己的数据。

临时表对于必须缓冲中间结果集的应用程序非常有用。

创建临时表

使用CREATE GLOBAL TEMPORARY TABLE 语句创建一个临时表。ON COMMIT子句指定表中的数据是特定于事务 (默认值),还是特定于会话

与其它一些关系数据库中的临时表不同,当你在 Oracle数据库中创建一个临时表时,你只创建其静态表定义。临时表是在数据字典中所描述的一个持久对象,但在您的会话向表中插入数据之前,表显示为空。你是在为数据库本身创建一个临时表,而不是为每个 PL/SQL 存储过程。

因为临时表是静态定义的,您可以使用CREATE INDEX 语句为其创建索引。临时表上创建的索引也是临时的。在索引中的数据与临时表中的数据具有相同的会话或事务范围。您还可以在临时表上创建一个视图或触发器。

临时表中的段分配

与永久表类似,临时表被定义在数据字典中。但是,临时表和他们的索引不会在创建时自动分配段。相反,临时段是在第一次插入数据时分配的。在一个会话中加载数据之前,表显示为空。对特定事务的临时表,临时段在事务结束时释放空间,而对特定于会话的临时表,在会话结束时释放空间。

外部表

外部表访问外部数据源中的数据,如同此数据是在数据库中的表中一样。*您可以使用 SQL 、 PL/SQL、和 Java 查询外部数据*。

外部表可用于查询平面文件。例如,一个基于 SQL 的应用程序,可能需要访问一个文本文件中的记录。记录的形式如下:

100,Steven,King,SKING,515.123.4567,17-JUN-03,AD_PRES,31944,150,90101,Neena,Kochhar,NKOCHHAR,515.123.4568,21-SEP-05,AD_VP,17000,100,90102,Lex,De Haan,LDEHAAN,515.123.4569,13-JAN-01,AD_VP,17000,100,90

您可以创建一个外部表,把这个文件复制到外部表定义中指定的位置,并使用 SQL 查询该文本文件中的记录。

外部表对于在数据仓库环境中执行常见的ETL任务也是很有价值的。例如,外部表使得数据加载阶段和数据转换阶段对接,消除了为进一步处理数据库中的数据而在数据库内存放中间数据的需要。

创建外部表

在数据库内部,创建一个外部表意味着在数据字典中创建元数据。与普通的表不同,外部表不描述存储在数据库中的数据,也不会描述数据在外部是如何存储的。外部表的元数据描述了外部表层必须如何提供数据给数据库。

CREATE TABLE … ORGANIZATION EXTERNAL语句包含两部分。外部表定义描述列类型。这个定义像一个视图,使您可以使用SQL查询外部数据,而不用将其加载到数据库。该语句的第二部分将外部数据映射到列。

外部表是只读的,除非它是使用 CREATE TABLE AS SELECT 和 ORACLE_DATAPUMP 访问驱动程序创建的。外部表有些限制,包括不支持索引列、 虚拟列、和列对象。

外部表访问驱动程序

访问驱动程序是一个 API,它为数据库解释外部数据。访问驱动程序在数据库内运行,数据库使用该驱动程序来读取外部表中的数据。访问驱动程序和外部表层负责对数据文件中的数据进行转换,使它与外部表定义匹配。

这里写图片描述

Oracle为外部表提供了 ORACLE_LOADER(缺省) 和 ORACLE_DATAPUMP 访问驱动程序。对于这两个驱动程序来说,外部文件不是 Oracle 数据文件(,而只是普通操作系统文件)。

ORACLE_LOADER 允许通过SQL*Loader对外部文件进行只读访问。您不能使用 ORACLE_LOADER 驱动程序创建、 更新、或追加数据到外部文件。

ORACLE_DATAPUMP 驱动程序使您能够卸载外部数据。此操作包括从数据库读取数据,并将其插入到由一个或多个外部文件所代表的外部表中。创建外部文件后,无法更新或将追加数据到外部文件。该驱动程序也使您能够加载外部数据,包括读取外部表并将其数据加载到数据库中。

表存储

Oracle 数据库使用表空间中的数据段保存表数据。段包含由数据块组成的扩展盘区。表数据段(或涉及表簇时的簇数据段)位于表所有者的默认空间中,或 CREATE TABLE 语句中所指定的表空间中。

表组织

默认情况下,表按堆的形式来组织数据,这意味着数据库将行存放在最适合他们的位置,而不是按用户指定的顺序来存放。因此,堆组织表是一个无序的行的集合当用户往其中添加行时,数据库将行置于在数据段中第一个可用的空闲空间。*不能保证行按照插入它们的顺序进行检索。*

注意

索引组织表使用不同的组织原则

列的顺序对于表中的所有行都是相同的通常,数据库按它们被列在 CREATE TABLE 语句中的列顺序来存储列,但这个顺序是不保证的。例如,如果表中有 LONG 类型的列,那么数据库总是将其存储到行中的最后一列此外,如果向表中添加一个新列,则新列将被存储为最后一列。

与常规列不同,表可以包含虚拟列,它不占用磁盘上的空间。数据库通过计算一组用户指定的表达式或函数,在虚拟列中按需派生一个值。您可以对虚拟列创建索引、 收集统计数据、并创建完整性约束。因此,虚拟列非常像非虚拟列。

行存储

数据库将行存储在数据块中在表中,少于 256 个列的行,被存储在一个或多个行片中。

数据库尽可能将每一行作为一个行片来存储但是,如果所有的行数据不能插入到一个单一数据块中,或者对现有的行的更新导致行溢出,则数据库使用多个行片来存储此行

表簇中的行除了包含非聚集表中的行相同的信息,还包含对其所属簇键的引用信息。

行片Rowids

rowid 实际上是行的一个 10 字节的物理地址。堆组织表中的每一行都有一个在该表中唯一的rowid,与一个行片的物理地址相对应对于表簇,处于同一个数据块的不同表中的行可以有相同的 rowid

Oracle 数据库在内部使用 rowids来构建索引。例如,在 B-树索引中的每个键与一个指向关联行地址的rowid相关联,以便快速访问。物理 rowids 提供对表行尽可能最快的访问,使数据库几乎只需单次 I/O就可以检索到行。

表压缩

数据库可以使用表压缩来消除数据块中的重复值对于数据高度冗余的表,压缩可以节省磁盘空间,减少数据库高速缓存中的内存使用,并在某些情况下可以加快查询执行速度。*表压缩对数据库应用程序是透明的。*

基本/OLTP表压缩

基于字典的表压缩提供了很好的压缩率。Oracle 数据库支持以下类型的表压缩:

基本表压缩

这种类型的压缩只能压缩由直接路径加载插入的数据,只支持有限的数据类型和 SQL 操作。

OLTP表压缩

这种类型的压缩用于 OLTP 应用程序,并可压缩任何 SQL 操作的数据。

数据库以行主要格式存储压缩行。一个行的所有列都存储在一起,接下来是下一行的所有列,依次类推。重复值被替换为一个存储在块开始处的符号表短引用。因此,重新创建未压缩数据所需的信息存储在数据块本身中。

压缩的数据块看起来跟正常的数据块差不多。在常规数据块上能正常工作的大多数数据库功能,也可以在压缩的数据块上正常工作。

压缩声明

您可以在表空间、 表、 分区或子分区等级别声明压缩。如果在表空间级指定了压缩,则在该表空间中创建的所有表在缺省情况下都是压缩的。

下面的语句将 OLTP 压缩应用于orders表:

ALTER TABLE oe.orders COMPRESS FOR OLTP;

如下所示的 CREATE TABLE 语句示例片断,指定其中一个分区为 OLTP 压缩,而其他分区为基本压缩:

CREATE TABLE sales (prod_id NUMBER NOT NULL,cust_id NUMBER NOT NULL, ... )PCTFREE 5 NOLOGGING NOCOMPRESSPARTITION BY RANGE (time_id)( partition sales_2008 VALUES LESS THAN(TO_DATE(...)) COMPRESS BASIC,partition sales_2009 VALUES LESS THAN (MAXVALUE) COMPRESS FOR OLTP );

空值存储

空值是指在某个列中值的缺失。空值表示缺少、 未知、或不适用的数据。

在数据库中,如果在空值的前后都有数据值,则空值会被存储。在这些情况下,他们需要 1 个字节来存储列的长度(零)尾随的空值在行中不需要存储,因为新的行头标志着前一行中的剩余列都为空。例如,如果表的最后三列为空,则不为这些列存储数据。

表簇概述

表簇是一组表,它们共享公共的列,并将相关的数据存储在相同的数据块中当表被聚簇时,单个数据块可以包含多个表中的行。例如,一个块可以同时存储来自employees表和departments表的行,而不只是单个表中的行。

簇键是所有被聚簇的表的共有列或列集。例如,employees表和departments表共享 department_id 列。您在创建表簇时,和创建被添加到表簇的每个表时,指定簇键。

簇键值是一组特定行的簇键列的值。包含相同簇键值的所有数据(例如department_id=20),物理上存储在一起每个簇键值在簇或簇索引中只存储一次,而无论在这些不同表中有多少行包含这个值。

如果多个表主要是被查询 (而不是修改) ,且各表中的记录是经常被一起查询或联接,在这些情况下可以考虑将他们聚簇化。因为表簇将不同表中的相关行存储在同一个数据块中,被正确使用的表簇相比非聚簇表具有下列优点:

 对于被聚簇表的联接,可以减少磁盘 I/O
 对于被聚簇表的联接,可以提高访问速度。
 只需更少的空间来存储相关的表和索引数据,因为簇键值不会为每行重复存储。

通常,簇表不适合以下情况:

 会经常被更新的表。
 经常需要全表扫描的表。
 需要被截断的表。

索引化表簇概述

索引化聚簇是使用索引来查找数据的表簇。而簇索引是一个簇键上的 B 树索引。簇索引必须先被创建,然后才能将行插入到簇表中。

假定使用簇键 department_id来创建聚簇 employees_departments_cluster 。因为未指定 HASHKEYS 子句,这个簇是一个索引化表簇。然后,在这个簇键上创建一个名为 idx_emp_dept_cluster 的索引

CREATE CLUSTER employees_departments_cluster(department_id NUMBER(4))SIZE 512;CREATE INDEX idx_emp_dept_cluster ON CLUSTER employees_departments_cluster;CREATE TABLE employees ( ... )CLUSTER employees_departments_cluster (department_id);CREATE TABLE departments ( ... )CLUSTER employees_departments_cluster (department_id);

最后,将行添加到employees表和departments表中。数据库在物理上将雇员表和部门表中每个部门的所有行都存储在相同的数据块中。数据库以堆的形式存储行,并使用索引定位他们

下图显示了包含employees表和departments表所构成的 employees_departments_cluster 表簇。数据库将部门 20的雇员所在的行存储在一起,部门110 的行也存储在一起,依次类推。如果表未被聚簇,那么数据库将不保证相关的行被存储在一起。

这里写图片描述

B 树簇索引把簇键值与数据所在块的数据库块地址 (DBA) 关联起来。例如,键 20的索引条目显示包含部门 20的雇员数据所在块的地址:

20,AADAAAA9d

与非聚簇表上的索引类似,簇索引被单独管理,簇索引也可以与表簇存在于不同的表空间中。

哈希簇概述

除了索引键被替换为一个哈希函数之外,哈希簇就像一个索引化聚簇。它没有单独的簇索引存在。对一个哈希簇来说,数据本身就是索引。

对已索引的表或索引化聚簇,数据库用存储在一个单独的索引中的键值查找表行。要查找或存储已索引的表或索引化聚簇中的一个行,数据库必须执行至少两个 I/O 操作:

为查找或存储在索引中的键值,需要一个或多个I/O
为读取或写入表或表簇中的行,还需要一个 I/O

为查找或存储在哈希簇中的一个行,数据库将哈希函数应用到行的簇键值。得出的哈希值对应到一个聚簇中的数据块,数据库则按发出的语句读写该块。

哈希是一种可选的表数据存储方法,用来提高数据检索的性能。在满足以下条件时,哈希簇可能是有益的:

 经常被查询,但不经常被修改的表。

哈希键列经常使用等值条件查询,例如, WHERE department_id = 20。对于这样的查询,簇键值是已经过哈希运算的。哈希键值直接指向存储行的磁盘区域。

 您可以合理地猜出哈希键的数目,和每个键值所存储的数据的大小。

创建哈希簇

与索引化聚簇的键类似,簇键是由簇中各表共享的单键列或复合键列。哈希键值是插入到簇键列的实际值或可能值。例如,如果簇键是 department_id,那么哈希键键值可能是 10、 20、 30,等等。

Oracle 数据库使用一个哈希函数,接受任意多个哈希键值作为输入,经过排序并哈希到有限数量的桶。每个桶都有一个唯一的数字 ID,称为哈希值。

每个哈希值都映射到哈希键值(部门 10、 20、 30,等等)对应行所在块的数据库块地址。

与创建索引化聚簇类似,使用CREATE CLUSTER语句创建一个哈希簇,但得加上一个哈希键。哈希值的数量取决于哈希键。示例 中可能存在的部门的数量是 100,所以 HASHKEYS 设置为 100。

CREATE CLUSTER employees_departments_cluster(department_id NUMBER(4))SIZE 8192 HASHKEYS 100;

创建聚簇 employees_departments_cluster 后,可以在该簇中创建employees表和departments表。然后可以将数据装载到哈希簇中,如同示例中所述的索引化簇一样。

查询哈希簇

由数据库(而不是用户)确定如何哈希用户输入的键值。例如,假设用户经常执行如下的查询, 为p_id输入不同的部门 ID 号:

SELECT *FROM employeesWHERE department_id = :p_id;SELECT *FROM departmentsWHERE department_id = :p_id;SELECT *FROM employees e, departments dWHERE e.department_id = d.department_idAND d.department_id = :p_id;

如果某个用户查询department_id = 20的雇员,那么数据库可能将此值哈希到桶 77。如果某个用户查询department_id = 10的雇员,那么数据库可能将此值哈希到桶 15。数据库使用内部生成的哈希值来定位包含请求的部门的雇员行所在的数据块。

图 2-6 将哈希簇段显示为一行水平排列的块。如图所示,查询只需单个 I/O就可以检索到数据。

这里写图片描述

哈希簇的一个限制是在非索引化簇键上的范围扫描不可用。假设在示例 2-9 中没有为哈希簇创建单独的索引。对部门 id在 20 和 100 之间的查询不能使用哈希算法,因为它不能哈希 20 和 100 之间的每个可能的值。因为没有索引存在,数据库必须执行完全扫描。

哈希簇变体

单表哈希簇是哈希簇的一个优化版本,一次只支持一个表。哈希键和行之间存在一一映射。当用户需要通过主键快速访问表时,单表哈希簇会很有用。例如,用户经常通过employee_id查找一个雇员表中的雇员记录。

排序哈希簇存储哈希函数的每个值对应的行,通过某种方式,数据库可以有效地把他们按已排定的顺序返回。数据库在内部执行优化的排序。对于需要总是按排定顺序来消费数据的应用程序,这种技术可能会更快的检索到数据。例如,应用程序可能总是按订单表的 order_date 列进行排序。

哈希簇存储

Oracle 数据库为哈希簇分配空间的方式不同于索引化簇。在示例 2-9中, HASHKEYS 指定可能存在的部门数,而SIZE指定与每个部门相关联的数据的大小。则数据库将基于以下公式计算存储空间:

HASHKEYS * SIZE / database_block_size

因此,如果示例 2-9中的块大小是 4096 字节,那么数据库至少要为该哈希簇分配200 个数据块。

Oracle 数据库并不限制您可以向哈希簇中插入的哈希键值的数目。例如,即使 HASHKEYS 是 100,但这不会阻止你向部门表中插入 200个不同的部门。但是,当(输入的)哈希键值的数目超过哈希键(HASHKEYS的设定)数目时,哈希簇检索效率会降低。

为说明检索问题,假定图 2-6中的块 100内全是部门 20的行。用户向部门表中插入一个新的部门,其 department_id 为43。部门的数量超过 HASHKEYS 的值,因此数据库对department_id 43进行哈希处理得到哈希值 77,这与department_id 20的哈希值相同。多个输入的值被哈希为相同的输出值称为哈希冲突。

当用户为部门43 往簇中插入行时,数据库不能将这些行存储在块 100中,因为它已经满了。数据库将块 100链接到一个新的溢出块,比如说块 200,并将插入的行存储在新块中。这两个块 100 和 200 现在都可以存储部门20或43的数据。如图 2-7 ,查询部门 20 或 43现在需要两个 i/o 才能检索到数据: 块 100 和其相关联的块200。您可以通过重新创建具有不同HASHKEYS 值的表簇来解决这个问题。

这里写图片描述

0 0
原创粉丝点击