通过案例学调优之--Oracle Cluster Table

通过案例学调优之--Oracle Cluster Table

About Clusters

A cluster provides an optional method of storing table data. A cluster is made up of a group of tables that share the same data blocks. The tables are grouped together because they share common columns and are often used together. For example, the emp and dept table share the deptno column. When you cluster the emp and dept tables (see Figure 18-1), Oracle Database physically stores all rows for each department from both the emp and dept tables in the same data blocks.

Because clusters store related rows of different tables together in the same data blocks, properly used clusters offer two primary benefits:

  • Disk I/O is reduced and access time improves for joins of clustered tables.
  • The cluster key is the column, or group of columns, that the clustered tables have in common. You specify the columns of the cluster key when creating the cluster. You subsequently specify the same columns when creating every table added to the cluster. Each cluster key value is stored only once each in the cluster and the cluster index, no matter how many rows of different tables contain the value.

    Therefore, less storage might be required to store related table and index data in a cluster than is necessary in non-clustered table format. For example, in Figure 18-1, notice how each cluster key (each deptno) is stored just once for many rows that contain the same value in both the emp and dept tables.

After creating a cluster, you can create tables in the cluster. However, before any rows can be inserted into the clustered tables, a cluster index must be created. Using clusters does not affect the creation of additional indexes on the clustered tables; they can be created and dropped as usual.

You should not use clusters for tables that are frequently accessed individually.

 索引簇的工作原理:

       聚簇:如果一组表有一些共同的列,则将这样一组表存储在相同的数据库块中;聚簇还表示把相关的数据存储在同一个块上。利用聚簇,一个块可能包含多个表的数据。概念上就是如果两个或多个表经常做连接操作,那么可以把需要的数据预先存储在一起。聚簇还可以用于单个表,可以按某个列将数据分组存储。

  更加简单的说,比如说,EMP表和DEPT表,这两个表存储在不同的segment中,甚至有可能存储在不同的TABLESPACE中,因此,他们的数据一定不会在同一个BLOCK里。而我们有会经常对这两个表做关联查询,比如说:select * from emp,dept where emp.deptno = dept.deptno .仔细想想,查询主要是对BLOCK的操作,查询的BLOCK越多,系统IO就消耗越大。如果我把这两个表的数据聚集在少量的BLOCK里,查询效率一定会提高不少。

  比如我现在将值deptno=10的所有员工抽取出来,并且把对应的部门信息也存储在这个BLOCK里(如果存不下了,可以为原来的块串联另外的块)。这就是索引聚簇表的工作原理。

案例分析:

创建簇的 格式

CREATE CLUSTER cluster_name
    (column date_type [,column datatype]...)
    [PCTUSED 40 | integer] [PCTFREE 10 | integer]
    [SIZE integer]
    [INITRANS 1 | integer] [MAXTRANS 255 | integer]
    [TABLESPACE tablespace]
    [STORAGE storage]

SIZE:指定估计平均簇键,以及与其相关的行所需的字节数。

1) 普通表连接查询

10:06:37 [email protected] test1>conn scott/tiger
Connected.

11:47:08 [email protected] test1 >select e.ename,e.sal,e.deptno,d.dname,d.loc from emp e ,dept d
11:48:21   2   where e.deptno=d.deptno and d.deptno=10;

ENAME             SAL     DEPTNO DNAME          LOC
---------- ---------- ---------- -------------- -------------
CLARK            2450         10 ACCOUNTING     NEW YORK
KING             5000         10 ACCOUNTING     NEW YORK
MILLER           1300         10 ACCOUNTING     NEW YORK

Execution Plan
----------------------------------------------------------
Plan hash value: 568005898
----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     3 |    99 |     4   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |         |     3 |    99 |     4   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    20 |     1   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)| 00:00:01 |
|*  4 |   TABLE ACCESS FULL          | EMP     |     3 |    39 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("D"."DEPTNO"=10)
   4 - filter("E"."DEPTNO"=10)
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
         10  consistent gets
          0  physical reads
          0  redo size
        766  bytes sent via SQL*Net to client
        419  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          3  rows processed
          
17:46:11 [email protected] test1 >select dbms_rowid.ROWID_OBJECT(rowid) "OBJ",DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) "BLOCK_ID" FROM EMP WHERE ROWNUM=1;

       OBJ   BLOCK_ID
---------- ----------
     17571        149

Elapsed: 00:00:00.01
17:46:40 [email protected] test1 >select dbms_rowid.ROWID_OBJECT(rowid) "OBJ",DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) "BLOCK_ID" FROM DEPT WHERE ROWNUM=1;

       OBJ   BLOCK_ID
---------- ----------
     17569        133
     
对于emp和dept表,属于不同的object,数据存储在不同的数据块上。

2)簇表查询

------建立簇
create cluster dept_emp_clu (deptno number(3))
  pctfree 20 pctused 60
  size 500 tablespace users;
  
--- 建立簇表
  
  create table department(
  id number(3) primary key,
  dname varchar(14) ,loc varchar2(13))
  cluster dept_emp_clu(id);
  
  create table employee(
  eno number(4) primary key ,
  ename varchar2(10),
  job varchar2(9),
  mgr number(4),
  hiredate date,
  sal number(7,2),
  comm number(7,2),
  dept_id number(3) references department
  ) cluster dept_emp_clu(dept_id);
  
-----在簇上建立索引
  create index dept_emp_idx on cluster dept_emp_clu
   tablespace indx;
   
11:49:43 [email protected] test1 >analyze table department compute statistics;
Table analyzed.
Elapsed: 00:00:00.09
11:50:15 [email protected] test1 >analyze table employee compute statistics;
Table analyzed.
Elapsed: 00:00:00.09
11:50:31 [email protected] test1 >select e.ename,e.sal,e.DEPT_ID,d.dname,d.loc from employee e,department d
11:50:39   2  where e.dept_id=d.id and d.id=10; 
ENAME             SAL    DEPT_ID DNAME          LOC
---------- ---------- ---------- -------------- -------------
CLARK            2450         10 ACCOUNTING     NEW YORK
KING             5000         10 ACCOUNTING     NEW YORK
MILLER           1300         10 ACCOUNTING     NEW YORK
Elapsed: 00:00:00.00
Execution Plan
----------------------------------------------------------
Plan hash value: 2165989181
---------------------------------------------------------------------------------------------
| Id  | Operation                    | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |              |     5 |   140 |     2   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |              |     5 |   140 |     2   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPARTMENT   |     1 |    18 |     1   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | SYS_C005404  |     1 |       |     0   (0)| 00:00:01 |
|   4 |   TABLE ACCESS CLUSTER       | EMPLOYEE     |     5 |    50 |     1   (0)| 00:00:01 |
|*  5 |    INDEX UNIQUE SCAN         | DEPT_EMP_IDX |     1 |       |     0   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("D"."ID"=10)
   5 - access("E"."DEPT_ID"=10)
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          5  consistent gets
          0  physical reads
          0  redo size
        767  bytes sent via SQL*Net to client
        419  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          3  rows processed
          
   对于Cluster table连接访问,可以看到“5  consistent gets“,比普通表”10  consistent gets“减少了一半的一致性读。
       
10:16:53 [email protected] test1>conn scott/tiger
Connected.
10:19:04 [email protected] test1>select rowid,ename from employee where rownum =1;
ROWID              ENAME
------------------ ----------
AAACiCAAEAAAACEAAA SMITH

10:19:05 [email protected] test1>select rowid,dname from department where rownum=1;
ROWID              DNAME
------------------ --------------
AAACiCAAEAAAACEAAA ACCOUNTING

17:49:17 [email protected] test1 >select dbms_rowid.ROWID_OBJECT(‘AAACiCAAEAAAACEAAA‘) "OBJ",DBMS_ROWID.ROWID_BLOCK_NUMBER(‘AAACiCAAEAAAACEAAA‘) "BLOCK_ID" FROM DUAL;

       OBJ   BLOCK_ID
---------- ----------
     10370        132
------因为簇表的数据放在相同的块上,所以在表连接查询时,减少了I/O

散列聚簇表

在簇表中,Oracle使用存储在索引中的键值来定位表中的行,而在散列聚簇表中,使用了散列函数代替了簇索引,先通过内部函数或者自定义的函数进行散列计算,然后再将计算得到的码值用于定位表中的行。创建散列簇需要用到HASHKEYS子句。     
1、创建散列簇     
create cluster my_clu_two(empno number(10) )    
pctused 70    
pctfree 10    
tablespace users    
hash is empno    
hashkeys 150 ;     
说明:    
* hash is 子句指明了进行散列的列,如果列是唯一的标示行,就可以将列指定为散列值    
* hashkeys 指定和限制散列函数可以产生的唯一的散列值的数量     
2、创建散列表     
create table t2_emp (      
empno number ( 10 ),      
ename varchar2 ( 20 ),      
birth_date date ,      
deptno number )    
cluster my_clu_two(empno);     
注意:    
* 必须设置数值的精度(具体原因不详)    
* 散列簇不能也不用创建索引    
* 散列簇不能ALTER:size、hashkeys、hash is参数

簇表的应用:

什么时候不应该使用聚簇:

  1) 如果预料到聚簇中的表会大量修改:必须知道,索引聚簇会对DML的性能产生某种负面影响(特别是INSERT语句)。管理聚簇中的数据需要做更多的工作。

  2) 如果需要对聚簇中的表执行全表扫描:不只是必须对你的表中的数据执行全面扫描,还必须对(可能的)多个表中的数据进行全面扫描。由于需要扫描更多的数据,所以全表扫描耗时更久。

  3) 如果你认为需要频繁地TRUNCATE和加载表:聚簇中的表不能截除。这是显然的,因为聚簇在一个块上存储了多个表,必须删除聚簇表中的行。

  因此,如果数据主要用于读(这并不表示“从来不写”;聚簇表完全可以修改),而且要通过索引来读(可以是聚簇键索引,也可以是聚簇表上的其他索引),另外会频繁地把这些信息联结在一起,此时聚簇就很适合。

补充关于需要使用聚簇表的情况:

考虑对经常在连接语句中访问的表建立聚簇。

如果表只是偶尔被连接或者它们的公共列经常被修改,则不要聚簇表。(修改记录的聚簇键值比在非聚簇的表中修改此值要花费更多的时间,因为Oracle 必须将修改的记录移植到其他的块中以维护聚簇)。

如果经常需要在一个表上进行完全搜索,则不要聚簇这个表(对一个聚簇表进行完全搜索比在非聚簇表上进行完全搜索的时间长,Oracle 可能要读更多的块,因为表是被一起存储的。)

如果经常从一个父表和相应的子表中查询记录,则考虑给1 对多(1:* )关系创建聚簇表。(子表记录存储在与父表记录相同的数据块中,因此当检索它们时可以同时在内存中,因此需要Oracle 完成较少的I/O )。

如果经常查询同一个父表中的多个子记录,则考虑单独将子表聚簇。(这样提高了从相同的父表查询子表记录的性能,而且也没有降低对父表进行完全搜索的性能)。

如果从所有有相同聚簇键值的表查询的数据超过一个或两个Oracle 块,则不要聚簇表。(要访问在一个聚簇表中的记录,Oracle 读取所有包含那个记录值的全部数据块,如果记录占据了多个数据块,则访问一个记录需要读的次数比一个非聚簇的表中访问相同的记录读的次数要多)。

使用哈希聚簇指南:

当经常使用有相同列的包含相等条件的查询子句访问表时,考虑使用哈希聚簇来存储表。使用这些列作为聚簇键。

如果可以确定存放具有给定聚簇键值的所有记录所需的空间(包括现在的和将来的),则将此表以哈希聚簇存储。

如果空间不够,并且不能为将要插入的新记录分配额外的空间,那么不要使用哈希聚簇。

如果偶尔创建一个新的、很大的哈希聚簇来保存这样的表是不切实际的,那么不要用哈希聚簇存储经常增长的表。

如果经常需要进行全表搜索,并且必须要为表的预期增长中的哈希聚簇分配足够的空间,则不要将此表以哈希聚簇存储。(这样的完全检索必须要读分配给哈希聚簇的全部块,即使有些块可能只包含很少的记录。单独地存储表将减少由完全的表检索读取的块的数量。)

如果你的应用程序经常修改聚簇键的值,则不要将表以哈希聚簇方式存储。

不管这个表是否经常与其他表连接,只要进行哈希对于基于以前的指南的表是合适的,那么在哈希聚簇中存储一个表可能是有用的。

时间: 2024-10-05 00:41:50

通过案例学调优之--Oracle Cluster Table的相关文章

通过案例学调优之--Oracle参数(db_file_multiblock_read_count)

通过案例学调优之--Oracle参数(db_file_multiblock_read_count) 应用环境: 操作系统: RedHat EL55 Oracle:   Oracle 10gR2   Oracle DB_FILE_MULTIBLOCK_READ_COUNT是Oracle比较重要的一个全局性参数,可以影响系统级别及sessioin级别.主要是用于设置最小化表扫描时Oracle一次按顺序能够读取的数据块数.通常情况下,我们看到top events中的等待事件db file scatte

通过案例学调优之--Oracle中null使用索引

通过案例学调优之--Oracle中null使用索引  默认情况下,Oracle数据库,null在Index上是不被存储的,当在索引列以"is null"的方式访问时,无法使用索引:本案例,主要向大家演示如何在存在null的索引列上,使用"is null"访问索引. 案例分析: 1.建立表和普通索引 13:52:23 [email protected] prod >create table t2 (x int,y int); Table created. 14:

通过案例学调优之--Oracle 全文索引

通过案例学调优之--Oracle 全文索引 全文检索(oracle text)  Oracle Text使Oracle9i具备了强大的文本检索能力和智能化的文本管理能力,Oracle Text 是 Oracle9i 采用的新名称,在 oracle8/8i 中被称为 oracle intermedia text,oracle8 以前是 oracle context cartridge.Oracle Text 的索引和查找功能并不局限于存储在数据库中的数据. 它可以对存储于文件系统中的文档进行检索和

通过案例学调优之--Oracle Time Model(时间模型)

通过案例学调优之--Oracle Time Model(时间模型) 数据库时间  优化不仅仅是缩短等待时间.优化旨在缩短最终用户响应时间和(或)尽可能减少每个请求占用的平均资源.有时这些目标可同时实现,而有时则需要进行折衷(如在并行查询时).通常可以认为,优化就是避免以浪费的方式占用或保留资源. 对数据库发出的任何请求都由两个不同的段组成:等待时间(数据库等待时间)和服务时间(数据库 CPU 时间).等待时间是各种数据库实例资源的所有等待时间的总和.CPU 时间是实际处理请求时消耗的时间的总和.

通过案例学调优之--Oracle数据块(block)

数据块概述Oracle对数据库数据文件(datafile)中的存储空间进行管理的单位是数据块(data block).数据块是数据库中最小的(逻辑)数据单位.与数据块对应的,所有数据在操作系统级的最小物理存储单位是字节(byte).每种操作系统都有一个被称为块容量(block size)的参数.Oracle每次获取数据时,总是访问整个数(Oracle)数据块,而不是按照操作系统块的容量访问数据. 数据库中标准的数据块(data block)容量是由初始化参数 DB_BLOCK_SIZE 指定的.

通过案例学调优之--SQL Profile

通过案例学调优之--SQL Profile 一.什么是SQL Profile(概要) SQL Profile在性能优化中占有一个重要的位置. MOS里这么描述SQL Profile: SQL Profile是10g中的新特性,作为自动SQL调整过程的一部分,由Oracle企业管理器来管理.除了OEM,SQL Profile可以通过DBMS_SQLTUNE包来进行管理. 查询优化器有时候会因为缺乏足够的信息,而对一条SQL语句做出错误的估计,生成糟糕的执行计划.而自动SQL调整通过SQL概要分析来

通过案例学调优之--模拟buffer busy waits事件

通过案例学调优之--模拟buffer busy waits事件 buffer busy waits等待事件     Wait occurs when a session attempts to access a block in memory, is denied and must wait until the buffer becomes available. This event happens because a buffer is either being read into the b

通过案例学调优之--RECORDS_PER_BLOCK参数

通过案例学调优之--RECORDS_PER_BLOCK参数      RECORDS_PER_BLOCK参数用于设定每个BLOCK中记录数的最大值,其先找到当前表所有BLOCK中容纳的最大行数,并会把这个数字记录到数据字典,以后任何导致BLOCK行数超过这个数字的插入都会被拒绝. RECORDS_PER_BLOCK参数是为位图索引而生的,能够改善位图索引的存储,减小位图索引的长度.这样,利用该位图索引的时候,就能获得比较好的效率了.     测试案例: 1.表默认的存储分析 15:45:46 [

通过案例学调优之--分区表基本概念

通过案例学调优之--分区表基本概念 Introduction to Partitioning Partitioning addresses key issues in supporting very large tables and indexes by letting you decompose them into smaller and more manageable pieces called partitions. SQL queries and DML statements do no