`

Oracle 聚簇(收集)

阅读更多

1. 什么是聚簇

聚簇是根据码值找到数据的物理存储位置,从而达到快速检索数据的目的。Oracle聚簇索引的顺序就是数据的物理存储顺序,叶节点就是数据节点。非聚簇索引的顺序与数据物理排列顺序无关,叶节点仍然是索引节点,只不过有一个指针指向对应的数据块。一个表最多只能有一个聚簇索引。

2. 使用 Oracle聚簇索引

聚簇是一种存储表的方法,这些表密切相关并经常一起连接进磁盘的同一区域。例如,表 BOOKSHELF 和BOOKSHELF_AUTHOR 数据行可以一起插入到称为簇(Cluster)的单个区域中,而不是将两个表放在磁盘上的不同扇区上。簇键(Cluster Key)可以是一列或多列,通过这些列可以将这些表在查询中连接起来(例如,BOOKSHELF表和BOOKSHELF_AUTHOR表中的 Title列)。为了将表聚集在一起,必须拥有这些将要聚集在一起的表。

下面是create cluster命令的基本格式:

create cluster (column datatype [, column datatype]...) [other options];

cluster的名字遵循表命名约定,column datatype是将作为簇键使用的名字和数据类型。column的名字可以与将要放进该簇中的表的一个列名相同,或者为其他有效名字。下面是一个例子:

create cluster BOOKandAUTHOR (Col1 VARCHAR2(100));

这样就建立了一个没有任何内容的簇(象给表分配了一块空间一样)。COL1的使用对于簇键是不相干的,不会再使用它。但是,它的定义应该与要增加的表的主键相符。接下来,建立包含在该簇中的表:
create table BOOKSHELF
(Title VARCHAR2(100) primary key,
Publisher VARCHAR2(20),
CategoryName VARCHAR2(20),
Rating VARCHAR2(2),
constraint CATFK foreign key (CategoryName) references CATEGORY(CategoryName)
)
cluster BOOKandAUTHOR(Title);

在向BOOKSHELF表中插入数据行之前,必须建立一个Oracle聚簇索引:

create index BOOKandAUTHORndx on cluster BOOKandAUTHOR;

在上面的create table语句中,簇BOOKandAUTHOR(Title)子句放在表的列清单的闭括号的后面。BOOKandAUTHOR是前面建立的聚簇的名字。

Title是将存储到聚簇Col1中的该表的列。create cluster语句中可能会有多个簇键,并且在created table语句中可能有多个列存储在这些键中。请注意,没有任何语句明确说明Title列进入到Col1中。这种匹配仅仅是通过位置做到的,即Col1和Title都是在它们各自的簇语句中提到的第一个对象。多个列和簇键是第一个与第一个匹配,第二个与第二个匹配,第三个与第三个匹配,等等。现在,添加第二个表到聚簇中:
create table BOOKSHELF_AUTHOR
(Title VARCHAR2(100),
AuthorName VARCHAR2(50),
constraint TitleFK Foreign key (Title) references BOOKSHELF(Title),
constraint AuthorNameFK Foreign key (AuthorName) references AUTHOR(AuthorName)
)
cluster BOOKandAUTHOR (Title);

当这两个表被聚在一起时,每个唯一的Title在簇中实际只存储一次。对于每个Title,都从这两个表中附加列。

来自这两个表的数据实际上存放在一个位置上,就好像簇是一个包含两个表中的所有数据的大表一样。

3. 散列聚簇

对于散列聚簇,它只有一个表。它通过散列算法求出存储行的物理存储位置,从而快速检索数据。创建散列聚簇时要指定码列的数据类型,数据行的大小及不同码值的个数。如果码值不是平均分布的,就可能有许多行存储到溢出块上,从而会降低查询该表的SQL语句的性能。

散列聚簇被用在总是通过主键查询数据的情况,例如要从表 T 查询数据并且查询语句总是是这样:

select * from T where id = :x;

这时散列聚簇是一个好的选择,因为不需要索引。Oracle 将通过散列算法得到值 :x 所对应的物理地址,从而直接取到数据。不用进行索引扫描,只通过散列值进行一次表访问

 

索引聚簇表 适用范围

索引聚簇表
create cluster emp_dept_cluster
(deptno number(2)) size 1024;
size 1024 表示每个聚簇键值关联大约1024字节的数据,
oracle会在用这个数据库块上通过size计算最多可以放多少个簇
如果块是8KB,那么这个块上最多放7个聚簇键

 

向聚簇中放数据之前,需要先对聚簇建立索引.
create index emp_dept_cluster_idx on cluster emp_dept_cluster;

 

加载的方式应彩用一一对应的关系.加载完主表之后再加载从表

 

什么情况下不能用索引聚簇表
1)如果预料到聚簇中的表会大量修改,索引聚簇表会对DML的性能产生负面影响.
2)非常不适合对单表的全表扫描,因为只能引起对其它表的全表扫描
3)频繁对表进行TRUNCATE和加载,因为聚簇中的表是不能TRUNCATE的

 

SQL> truncate table dept;
truncate table dept
*
ERROR at line 1:
ORA-03292: Table to be truncated is part of a cluster

 

 

 

如果数据主要用来读,不怎么修改,并且逻辑上与聚簇连接想适合,最好使用索引聚簇表
oracle数据字典就是这样做的

 

SQL> set autotrace traceonly statistics
SQL> select a.deptno,b.ename from dept_02 a,emp_02 b where a.deptno=b.deptno and
a.deptno='30';

 

6 rows selected.

 

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 MERGE JOIN
2 1 INDEX (UNIQUE SCAN) OF 'dddd' (UNIQUE)
3 1 FILTER
4 3 TABLE ACCESS (FULL) OF 'EMP_02'

 


Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
5 consistent gets
0 physical reads
0 redo size
470 bytes sent via SQL*Net to client
495 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
6 rows processed

 

SQL> select a.deptno,b.ename from dept a,emp b where a.deptno=b.deptno and a.dep
tno='30';

 

6 rows selected.

 


Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 NESTED LOOPS
2 1 INDEX (UNIQUE SCAN) OF 'SYS_C002891' (UNIQUE)
3 1 TABLE ACCESS (CLUSTER) OF 'EMP'

 


Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
4 consistent gets --这里可以看出有点优点,在consistent gets上少了一块
0 physical reads
0 redo size
470 bytes sent via SQL*Net to client
495 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
6 rows processed

 

SQL> select a.deptno,b.ename from dept a,emp b where a.deptno=b.deptno;

 

14 rows selected.

 

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 NESTED LOOPS
2 1 TABLE ACCESS (FULL) OF 'EMP'
3 1 TABLE ACCESS (CLUSTER) OF 'DEPT'

 


Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
37 consistent gets --全表扫描真是too bad,没有办法,这里不适用索引聚簇表
0 physical reads
0 redo size
581 bytes sent via SQL*Net to client
495 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
14 rows processed

 

SQL> select a.deptno,b.ename from dept_02 a,emp_02 b where a.deptno=b.deptno;

 

14 rows selected.

 

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 NESTED LOOPS
2 1 TABLE ACCESS (FULL) OF 'EMP_02'
3 1 INDEX (UNIQUE SCAN) OF 'dddd' (UNIQUE)

 


Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
581 bytes sent via SQL*Net to client
495 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
14 rows processed

 

 

Oracle的聚簇因子对于查询IO的影响

 

Oracle中,对于同一个查询语句,有时候会很快的完成,有时候却很慢,但是表结构什么的完全一致,表中的数据也完全一致,这个具体是什么原因呢,就要从Index中的细节说起了。

在Oracle中的一个特殊的视图user_indexes中有一个特殊的列,名字是clustering_factor,这个值的内容就是如果访问表的整个表数据,会造成多少次数据库IO。我们可以通过下面的SQL语句来查看。

SELECT
A.INDEX_NAME,
B.NUM_ROWS,
B.BLOCKS,
A.CLUSTERING_FACTOR
FROM
USER_INDEXES A,
USER_TABLES B
WHERE
A.INDEX_NAME = ?
AND A.TABLE_NAME = B.TABLE_NAME

在这个SQL语句中,?代表的就是我们要检索的Index的名称。在表中数据有时候属于无序状态,这个时候的CLUSTERING_FACTOR比较接近NUM_ROWS,说明如果扫描整个表,每次都要根据Index来读取相应行的RowID,这个时候的IO操作很多,自然检索时间会比较长。如果数据有序的话,CLUSTERING_FACTOR比较接近BLOCKS,说明相邻的数据在一个块中,减少了IO操作数量,自然检索时间会大大降低。

 

下面这一段是Oracle 手册中关于CLUSTERING_FACTOR的说明:

Indicates the amount of order of the rows in the table based on the values of the index.

  • If the value is near the number of blocks, then the table is very well ordered. In this case, the index entries in a single leaf block tend to point to rows in the same data blocks.

  • If the value is near the number of rows, then the table is very randomly ordered. In this case, it is unlikely that index entries in the same leaf block point to rows in the same data blocks.

 

-------------------------------------------------------------------------------------------------------------

 

 

一次简单的性能优化诊断,聚簇因子过高导致全表扫描。

业务人员反映一个查询非常慢:
--------------------------------------------------------------------------------
select * from ab44 where aae002=201006;
--------------------------------------------------------------------------------

查看执行计划,是全表扫描
SQL> explain plan for select * from ab44 where aae002=201006;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 781340439

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10554 | 865K| 8777 (3)| 00:01:46 |
|* 1 | TABLE ACCESS FULL| AB44 | 10554 | 865K| 8777 (3)| 00:01:46 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------

1 - filter("AAE002"=201006)
已选择13行。


看看查询应该返回多少数据量,还有这个表有多少记录。
SQL> select count(*) from ab44 where aae002='201006';
COUNT(*)
----------
576
SQL> select count(*) from ab44;
COUNT(*)
----------
3310023

SQL> select 576/3310023 from dual;
576/3310023
-----------
.000174017

查询所需返回的行数仅占表的很小比例,如果有索引的话,应该索引扫描才对。
查看表的索引,发现在aae002字段上有一个复合索引,四个字段组成AAE002, AAE003, AAB001, AAE140。既然有索引,为什么没有使用呢?莫非是缺失统计信息。

查看表、索引、直方图的信息都有。而且统计信息相对还是比较新的。
SQL> select num_rows,blocks,avg_row_len from user_tables where table_name='AB44';
NUM_ROWS BLOCKS AVG_ROW_LEN
---------- ---------- -----------
3310017 44538 84
SQL> select distinct_keys,clustering_factor,num_rows from USER_IND_STATISTICS WHERE table_name='AB44' and index_name='PK_AB44';
DISTINCT_KEYS CLUSTERING_FACTOR NUM_ROWS
------------- ----------------- ----------
3309447 3299907 3309447
SQL> SELECT * FROM USER_HISTOGRAMS WHERE table_name='AB44';
略。。。。。。。。。。。。。。。。。。。。。。。。

查询到索引的统计信息的时候,发现索引的聚簇因子非常高,非常接近表的行数。重新分析表,依然如此。
修改聚簇因子后,查看执行计划,已经是索引扫描了。


begin
dbms_stats.set_index_stats(ownname => 'NCSI',indname => 'PK_AB44',clstfct => '7800');
end;
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------
-------------
Plan hash value: 1618544176
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10554 | 865K| 239 (1)| 00:00:03 |
| 1 | TABLE ACCESS BY INDEX ROWID| AB44 | 10554 | 865K| 239 (1)| 00:00:03 |
|* 2 | INDEX RANGE SCAN | PK_AB44 | 10554 | | 45 (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("AAE002"=201006)
已选择14行。

但是到这里并不能说一点是聚簇因子导致的,因为很可能是还有直方图的因素。查询列AAE002上的唯一值个数为420,而表的记录总数是330万,如果没有直方图的话,ORACLE评估返回的行数应该是3300000/420=7857条记录,按照这个记录量来看,返回的行数占表记录总数的0.2%.根据经验,应该也能使用到索引才对。
于是重新收集统计信息,取消直方图。查看执行计划,还是全表扫描。看来直方图在本例中所占影响因素较小,还是聚簇因子过大惹的祸。

暂时通过修改聚簇因子暂时改善了性能问题,晚上的时候,按照索引字段的顺序重新创建了表。
SQL>create table AB44_TEMP as select * from ab44 where 1=0;
SQL>INSERT /*+ append */INTO AB44_TEMP SELECT * FROM AB44 ORDER BY AAE002, AAE003, AAB001, AAE140;
SQL>commit;
SQL>drop table ab44;
SQL>alter table ab44_temp rename to ab44;

重新创建索引,分析表。重建后的聚簇因子只有60197,远远小于之前的 3299907。查看执行计划,也对了。

SQL> explain plan for select * from ab44 where aae002=201006;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
-------------
Plan hash value: 2627288474
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10799 | 885K| 249 (1)| 00:00:03 |
| 1 | TABLE ACCESS BY INDEX ROWID| AB44 | 10799 | 885K| 249 (1)| 00:00:03 |
|* 2 | INDEX RANGE SCAN | AB44_TEMP_IND | 10799 | | 50 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("AAE002"=201006)
已选择14行。


而且为了验证本例确实是由于聚簇因子过大占了决定因素。我把重建后的表直方图取消掉,重新查询,每一个AAE002的值都是索引扫描了。
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'NCSI',
TABNAME => 'AB44',
CASCADE => TRUE,
METHOD_OPT => 'for ALL columns SIZE 1');
END;

SQL>EXPLAIN PLAN FOR SELECT * FROM ab44 WHERE aae002=201002;
SQL>EXPLAIN PLAN FOR SELECT * FROM ab44 WHERE aae002=201006;
SQL>EXPLAIN PLAN FOR SELECT * FROM ab44 WHERE aae002=198701;
SQL>EXPLAIN PLAN FOR SELECT * FROM ab44 WHERE aae002=199101;

SQL> select object_name,operation,options from plan_table where id=2;
OBJECT_NAME OPERATION OPTIONS
-------------------- ------------------------------ --------------------
AB44_TEMP_IND INDEX RANGE SCAN
AB44_TEMP_IND INDEX RANGE SCAN
AB44_TEMP_IND INDEX RANGE SCAN
AB44_TEMP_IND INDEX RANGE SCAN
AB44_TEMP_IND INDEX RANGE SCAN


***********************************************************
聚簇因子

堆表的最大特征就是数据的存储独立性,即数据的存储与数据值没有任何关联地被存储在磁盘的任意位置上。从另外一个侧面来看,该特征也就意味着为了查 询我们所需要的数据必然要在磁盘的多个位置上进行查找。

所谓"任意位置"的深层含义是指能够把数据物理地存储在磁盘上的方法多种多样。这就是我们前面所介绍的随机存储方式,即允许数据被存储在磁盘的任意 位置上。然而,从另外一个角度来看,随机存储方式就是数据所占据的位置分散在不同的数据块上。

在这种存储状态下,查询相同数据所执行的物理读取数量会随着查询数据的分散程度而不同。例如,数据行1~10被分散存储在10个数据块与两个数据块 相比较,虽然两种情况逻辑读取的数据行数(都是10行)是相同的,但在物理(I/O)读取的数据块数上却相差5倍。

在关系型数据库中,不论在何种情况下,每次最少都需要读取一个数据块。尽管我们每次要求读取的是行,但是实际上每次读取的却是数据块。因此,如果能 够在内存中命中我们所需要查询的数据行,则在很大程度上就能够减少物理I/O的数量。

尽管在不同系统环境下会略有一些差异,但在一般情况下,从内存块上查询数据的速度比从磁盘块上查询数据的速度快30倍左右。由于数据被分散地存储在 多个数据块上,数据读取效率也同样会随着它们的分散程度的不同而不同。即,分散程度越高,数据读取效率越低;分散程度越低,数据读取效率越高。换言之,数 据被存储得越集中,数据读取效率越高;数据被存储得越分散,数据读取效率越低下。

我们知道,由于数据的物理存储方式是数据存储时决定的,且物理存储方式只能按照一种顺序存储数据,所以顺序一旦被决定就不能根据读取条件而随心所欲 地改变。因此,不论我们采用何种存储方式来存储数据,最终都会使得每一个列值的存储集中程度与其他列值的存储集中程度之间出现一定的差异(也就是表中各个 列值的存储集中程度相互之间存在着一定的差异)。例如,即使是同父同母的兄弟姐妹,他们与父母的相像程度也存在一定的差异。

聚簇因子是指,按照索引列值进行了排序的索引行序和对应表中数据行序的相似程度。这就好似把孩子与父母的相像程度用数值来表示一样。由于聚簇因子大 小对数据读取效率有着直接的影响,所以在后面将要说明的所有表类型中都会对聚簇因子予以详细说明。

在所有的表类型中,尤其是在堆表中,聚簇因子显得格外重要。现在让我们通过图1-3来进一步理解聚簇因子。

在图的中央可以看到存储着表中数据的数据块,在这些数据块中存储着很多行数据。为了便于说明,假定第一个列为日期,第二个列为项目,第三个列为数 量。INDEX1是基于日期列而创建的索引,INDEX2是基于项目列而创建的索引。在这里为简化问题省略了索引中的ROWID。

 
(点击查看大图)图1-3

通过仔细观察图1-3可以发现,在表中,按照日期的顺序对数据行进行了存储。对表中的行进行详细分析可以发现,由于数据中的日期就是行被插入的日 期,所以数据也就很自然地被存储在相似的位置上。还可以发现在连续的日期中间偶尔会出现相差比较远的日期,这主要是由于对行所执行的修改或删除操作所致。 也正是因为修改和删除操作才使得在当前数据块中出现了空余空间,并当其大小超过预先设置的特定值(PCTUSED)时,就将该数据块记录到Free List中以待再次使用。

实际上,通常对存储在表中的行执行删除操作并不会频繁出现,并且修改操作导致列的长度变短的情况也比较少见。通常我们会尽量重复使用现存数据而尽量 避免新增数据,因此,通常数据插入操作的情况同样也比我们想象的要少(这种现象虽然会随着表特征的不同而不同,但是通常都如此)。需要注意的是,在这里并 不是指所有的情况,在特殊的应用环境中并不一定是这样。

在索引中是按照索引列和ROWID进行排序的。在索引创建时,既可以按照升序(Ascending)也可以按照降序(Descending)进行排 序。不论是升序还是降序都与数据读取的效率有着密切的联系,因此,不论如何选择都要有其合理的理由,不能随心所欲,这部分内容将在本书的后面予以详细说 明。

我们经过分析行的读取情况,不仅能够发现数据的读取每次都是以数据块为单位,而且能够发现位于同一数据块中的行并没有遵循特定的顺序。这些索引行实 际上是按照索引列和ROWID来进行排序的。按照ROWID对索引行进行排序,实际上是按照物理数据文件的数据块号对数据块进行排序,然后再按照Slot 号码对数据块中的行进行排序。

由此可见,就像图1-3所示的那样,由于按照数据块的号码对数据块进行了排序,所以我们能够看出DBMS在以块为单位执行数据读取时,为了在一个数 据块中读取尽可能多的行所做的努力。尽管数据块中的行没有遵循特定的顺序,但利用Slot中所存储的行的位置信息也始终能够找到期望的行。

这也就意味着,在索引中按照ROWID进行排序只不过是在数据块中按照Slot号码进行了排序,这并不会对行的读取产生任何影响。在图1-3中,尽 管能够按照进行排序了的Slot号码读取数据块中的行,但也正是由于这个原因导致行读取顺序不规则现象的出现。

现在让我们再来分析一下,使用位于图1-3左右两侧的索引来读取特定范围中行的情况。我们可以看到,把相同的数据集中存储在两个数据块中位于左侧的 INDEX1,和把相同的数据分散存储在不同数据块中位于右侧的INDEX2。INDEX1虽然需要读取7行数据,但实际上却只读取了两个数据块;而 INDEX2虽然只需要读取3行数据,但却读取了3个数据块。

我们知道数据的存储方式一旦被决定,不论在何种情况下都不能随意改变。就像图1-3所示的那样,尽管索引是在表的基础上创建的,但索引行的顺序仍然 与表中行的位置在相似程度上存在着一定差异。因此,如果利用聚簇因子较好的索引读取数据,则即使所需要读取的行数较多,也能因为读取数据块数较少而能够获 得非常好的读取效率。由此可见,在频繁需要读取大范围数据(大范围数据是指位于开始行与结束行之间的满足查询条件的连续数据行,在本书中将其称之为大范围 数据)的情况下,为了提高读取效率而采用有利于数据读取的存储方式就会显得非常重要。

例如,要到达同一地点,则居住在交通便利但较远的地方,比居住在交通不便利但较近的地方要快。通常我们都会在交通要地修建高速公路、飞机场、高速铁 路等快速便利的交通设施。也正是由于这些便利的交通设施,才使得我们现在的生活和出行变得轻松方便。同理,如果以较小的代价就能够有效地处理经常需要访问 的大范围数据,则就可以获得非常好的效率。

如果表中行的存储顺序与我们经常读取较大范围行的顺序一致,则就能够在很大程度上提高读取效率。然而,这两种顺序的一致只不过是偶尔才会出现的现 象,大部分情况并非如此。因此为了提高数据的读取效率,就需要我们针对不同的情况制定出不同的战略措施,以提高聚簇因子。按照经常频繁读取的大范围数据的 读取顺序来存储数据、提高聚簇因子的措施中将会涉及多方面的因素。

事实上,提高聚簇因子的有效方法有很多,但这些方法的不足之处就在于在数据存储时需要付出的代价较大。在提高聚簇因子方面显得最无效的方法就是堆 表,因为这种表结构所采用的并不是对数据的存储具有强制性约束的固定存储方式,而是按照数据插入的顺序进行存储的随机存储方式。

如果通过少量额外代价就可以按我们所期望的方式来提高聚簇因子,则也算是实现了以较小代价换取较高读取效率的目的。这里所谓的"期望的方式"是指按 照特定的方法存储数据的方式。

即使我们所期望的数据存储顺序与数据生成的顺序不一致,也不应当为此而耿耿于怀。只需要定期对表执行重构操作就可以达到所期望的效果。然而,我们绝 对不可以忽视表重构操作的代价,而且它的代价并不像我们想象的那么小。因此,表的重构操作也不是随心所欲的事情。

尽管这里强调了表重构操作的代价并不小,但这只是为了让各位读者引起重视,事实上,表重构操作的代价并不是很大。即使表中存储的是海量数据也不用担 心,因为现在DBMS的功能不断提高,并且此项操作通常都是放在空闲时间来实施的,所以不会给系统造成太大的负担。另外,对表的重构操作并不一定要等到非 常需要时才去执行。重构操作的周期可能会随着实际情况的不同而不同,但即使几个月执行一次也同样能够充分地实现所期望的目的。

即使此项操作由于其他原因而搁置了一段时间,但除了聚簇因子稍微有所变坏之外,其他部分并不会受到任何影响,而可以将此项操作继续推迟到有空闲时间 时再去执行。如果为表创建了分区,则由于在此期间有可能只使用了一部分分区中的数据,就更加不会影响数据的读取效率了。对表的重构操作影响最大的因素是并 行处理(Parallel Processing)。

对于究竟应当按照哪个列的顺序存储数据的综合性战略方案,将在第4章予以系统说明。从某种意义上来看,这里所谓的索引战略方案与其说是为了索引的构 成形态而制定的战略方案,还不如说是通过对可能出现的所有读取类型的全面分析,制定出能够实现最优数据读取的最理想的索引战略方案。

鉴于此,在堆表结构中,应当从战略性的高度对将要存储的列的顺序,予以综合性的分析和判断。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics