索引 的聚簇因子对能否用到该索引的影响的实验

在理论学习中,我们了解到,索引的聚簇因子(clustering_factor)对CBO是否选择使用索引有很大的影响。所以,首先通过以下模拟实验来加深印象:

创建测试表t0403a,共两列(ID列和COL1列),其中ID列为一个1000以内的随机数。然后在ID列上创建索引。这样做的目的就是想让该索引的聚簇因子较大。因为用这种方式创建的表中数据存放顺序与ID的大小是完全不相关的,即是混乱的,不是有序的。

SQL> create table t0403a as select ceil(dbms_random.value*1000) id,rpad(rownum,50,‘a‘) col1 from dual connect by rownum<=1000;

Table created.

SQL> create index ind_t0403a on t0403a(id);

Index created.

SQL> exec dbms_stats.gather_table_stats(ownname=>‘SYS‘,tabname=>‘T0403A‘,estimate_percent=>100);

PL/SQL procedure successfully completed.

SQL> set autotrace on;

SQL> select * from t0403a where id<100;

ID COL1

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

57 12aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

12 36aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

47 38aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

40 39aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

69 42aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

59 47aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

32 48aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

31 50aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

32 58aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

69 67aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

77 68aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

--为节省篇幅,截短了输出

83 rows selected.

Execution Plan

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

Plan hash value: 1941751419

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

| Id  | Operation  | Name   | Rows  | Bytes | Cost (%CPU)| Time   |

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

|   0 | SELECT STATEMENT  |   |97 |  5335 | 4   (0)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| T0403A |97 |  5335 | 4   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

1 - filter("ID"<100)

Statistics

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

1  recursive calls

0  db block gets

22  consistent gets

0  physical reads

0  redo size

6183  bytes sent via SQL*Net to client

579  bytes received via SQL*Net from client

7  SQL*Net roundtrips to/from client

1  sorts (memory)

0  sorts (disk)

83  rows processed

SQL> select * from t0403a where id<6;

ID COL1

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

3 433aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

5 704aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Execution Plan

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

Plan hash value: 1941751419

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

| Id  | Operation  | Name   | Rows  | Bytes | Cost (%CPU)| Time   |

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

|   0 | SELECT STATEMENT  |   | 3 |   165 | 4   (0)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| T0403A | 3 |   165 | 4   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

1 - filter("ID"<6)

Statistics

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

0  recursive calls

0  db block gets

5  consistent gets

0  physical reads

0  redo size

750  bytes sent via SQL*Net to client

524  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

2  rows processed

--不断实验,发现直至ID<5,实际输出行为1行时,即大约为总记录的千分之一时,才使用了索引。

SQL> select * from t0403a where id<5;

ID COL1

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

3 433aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Execution Plan

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

Plan hash value: 2057097983

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

| Id  | Operation    | Name | Rows  | Bytes | Cost (%CPU)| Time |

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

|   0 | SELECT STATEMENT    | |     2 |   110 |     4   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T0403A |     2 |   110 |     4   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN    | IND_T0403A |     2 | |     2   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

2 - access("ID"<5)

Statistics

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

1  recursive calls

0  db block gets

4  consistent gets

0  physical reads

0  redo size

641  bytes sent via SQL*Net to client

524  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

1  rows processed

SQL> select * from t0403a where id<6;

ID COL1

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

3 433aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

5 704aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Execution Plan

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

Plan hash value: 1941751419

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

| Id  | Operation  | Name   | Rows  | Bytes | Cost (%CPU)| Time   |

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

|   0 | SELECT STATEMENT  |   | 3 |   165 | 4   (0)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| T0403A | 3 |   165 | 4   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

1 - filter("ID"<6)

Statistics

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

0  recursive calls

0  db block gets

5  consistent gets

0  physical reads

0  redo size

750  bytes sent via SQL*Net to client

524  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

2  rows processed

SQL> set autotrace off

--查看索引的聚簇因子,为873

SQL> select clustering_factor from user_indexes where index_name=‘IND_T0403A‘;

CLUSTERING_FACTOR

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

873

--查看表中数据使用的数据块的数量,为9个。

SQL> select blocks from user_tables where table_name=‘T0403A‘;

BLOCKS

----------

9

--再实验一下数据的存放顺序与索引的顺序高度一致的情况

SQL> drop table t0403a purge;

Table dropped.

SQL> create table t0403a as select rownum id,rpad(rownum,50,‘a‘) col1 from dual connect by rownum<=1000;

Table created.

SQL> create index ind_t0403a on t0403a(id);

Index created.

SQL> exec dbms_stats.gather_table_stats(ownname=>‘SYS‘,tabname=>‘T0403A‘,estimate_percent=>100);

PL/SQL procedure successfully completed.

--此时索引的聚簇因子为9

SQL> select clustering_factor from user_indexes where index_name=‘IND_T0403A‘;

CLUSTERING_FACTOR

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

9

--表大小没有变化,所以,表中数据所占用的数据块数仍为9

SQL> select blocks from user_tables where table_name=‘T0403A‘;

BLOCKS

----------

9

--再看一下这时,索引的表现

SQL> set autotrace on;

SQL> select * from t0403a where id<100;

ID COL1

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

1 1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

2 2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

3 3aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

4 4aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

5 5aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

6 6aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

7 7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

8 8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

9 9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

10 10aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

11 11aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

--为节省篇幅,截短了输出

99 rows selected.

Execution Plan

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

Plan hash value: 2057097983

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

| Id  | Operation    | Name | Rows  | Bytes | Cost (%CPU)| Time |

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

|   0 | SELECT STATEMENT    | |    99 |  5445 |     3   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T0403A |    99 |  5445 |     3   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN    | IND_T0403A |    99 | |     2   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

2 - access("ID"<100)

Statistics

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

10  recursive calls

0  db block gets

36  consistent gets

0  physical reads

0  redo size

7589  bytes sent via SQL*Net to client

590  bytes received via SQL*Net from client

8  SQL*Net roundtrips to/from client

4  sorts (memory)

0  sorts (disk)

99  rows processed

--从上可见,当输出行数为99行,占表中总行数的近10%时,仍可以使用索引。

--而且,继续不断尝试,发现直至id<223,输出行数为222行时,占表中总行数约22%时,仍可以使用索引。

SQL> select * from t0403a where id<223;

ID COL1

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

1 1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

2 2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

3 3aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

4 4aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

5 5aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

6 6aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

7 7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

8 8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

9 9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

10 10aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

11 11aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

--为节省篇幅,截短了输出

222 rows selected.

Execution Plan

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

Plan hash value: 2057097983

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

| Id  | Operation    | Name | Rows  | Bytes | Cost (%CPU)| Time |

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

|   0 | SELECT STATEMENT    | |   222 | 12210 |     4   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T0403A |   222 | 12210 |     4   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN    | IND_T0403A |   222 | |     2   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

2 - access("ID"<223)

Statistics

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

1  recursive calls

0  db block gets

34  consistent gets

0  physical reads

0  redo size

16455  bytes sent via SQL*Net to client

678  bytes received via SQL*Net from client

16  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

222  rows processed

SQL> select * from t0403a where id<224;

ID COL1

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

1 1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

2 2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

3 3aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

4 4aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

5 5aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

6 6aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

7 7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

8 8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

9 9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

10 10aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

11 11aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

--为节省篇幅,截短了输出

223 rows selected.

Execution Plan

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

Plan hash value: 1941751419

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

| Id  | Operation  | Name   | Rows  | Bytes | Cost (%CPU)| Time   |

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

|   0 | SELECT STATEMENT  |   |   223 | 12265 | 4   (0)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| T0403A |   223 | 12265 | 4   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

1 - filter("ID"<224)

Statistics

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

1  recursive calls

0  db block gets

26  consistent gets

0  physical reads

0  redo size

15679  bytes sent via SQL*Net to client

678  bytes received via SQL*Net from client

16  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

223  rows processed

SQL>

通过以上实验,说明索引的聚簇因子,会严重影响索引能否被使用。当表中数据的存储顺序与索引的排列顺序差异较大时,几乎只有单行返回的查询语句才能用上索引。反之,当表中数据的存储顺序与索引的排列顺序高度一致时,即使返回的行数占总行数的超过20%,仍可以用到索引。

但为什么会这样呢,这是因为当使用聚簇因子较高的索引时,其COST较高,当其高于全表扫描的代价时,CBO就会选择此时COST更小的全表扫描方法了。

CBO在计算索引范围扫描(IRS)的成本时,使用如下的公式:

IRS COST=I/O COST + CPU COST

其中I/O COST=INDEX ACCESS I/O COST + TABLE ACCESS I/O COST

进一步:

INDEX ACCESS I/O COST=BLEVEL+CEIL(#LEAF_BLOCKS*IX_SEL)

TABLE ACCESS I/O COST=CEIL(CLUSTERING_FACTOR*IX_SEL_WITH_FILTERS)

这就可以看到,对于一个使用同样的SQL创建的索引,其IX_SEL(索引选择率)和IX_SEL_WITH_FILTERS(带过滤的索引选择率)(注1)是一样的。但如上面实验上所示,索引是一样的,但如果数据的存放顺序是不一样的,其聚簇因子是会相差很大的。所以,我们可以得到的第一个推论就是:索引的聚簇因子越大,其进行索引范围扫描的COST越大。

注1:写此博文时,未找到对“IX_SEL_WITH_FILTERS”的明确解释,所以,仅从字面上进行了翻译和理解。

时间: 2024-10-06 22:44:36

索引 的聚簇因子对能否用到该索引的影响的实验的相关文章

聚簇(或者叫做聚集,cluster)索引和非聚簇索引

字典的拼音目录就是聚簇(cluster)索引,笔画目录就是非聚簇索引.这样查询“G到M的汉字”就非常快,而查询“6划到8划的字”则慢. 聚簇索引是一种特殊索引,它使数据按照索引的排序顺序存放表中.聚簇索引类似于字典,即所有词条在字典中都以字母顺序排列.聚簇索引实际上重组了表中的数据,所以你只能在表中建立一个聚簇索引. 当数据按值的范围查询时,聚簇索引就显得特别有用.因为所有SQLServer都必需先找到所查询范围的第一行,然后依次下去,直到该范围的最后一个值找到为止,并且保证了所有其他值也落在这

Oracle索引聚簇因子的含义及重要性

索引统计信息中需要我们最为重点关注的是CLUSTERING_FACTOR(聚簇因子). 在Oracle数据库中,聚簇因子是指按照索引键值排序的索引行和存储于对应表中数据行的存储顺序和相似度.Oracle是按照如下的算法来计算聚簇因子的值: 聚簇因子的初始值为1. Oracle首先定位到目标索引处于最左边的叶子块. 从最左边的叶子块的第一个索引键值所在的索引行开始顺序扫描,在顺序扫描的过程中,Oracle会比对当前索引行的rowid和它之前的那个索引行(它们是相邻的关系)的rowid,如果这两个r

堆组织表,索引组织表和索引聚簇表

--- 堆组织表就不说了,其索引中记录了记录所在位置的rowid,查找的时候先找索引,然后再根据索引rowid找到块中的行数据 索引组织表,其行数据以索引形式存放,因此找到索引,就等于找到了行数据. -- 堆组织表的数据是散放的,索引和表的数据是分离的 索引组织表的索引和数据是在一起的 -- 堆组织表的存储速度因为不用考虑排序, 所以存储速度会比较快. 但是要查找符合某个条件的记录, 就必须得读取全部的记录以便筛选.而这个时候为了加快查询速度, 索引就出现了, 索引是针对少量特定字段的值拿出来进

[转帖]堆组织表,索引组织表和索引聚簇表

https://www.cnblogs.com/youngerger/p/8446399.html --- 堆组织表就不说了,其索引中记录了记录所在位置的rowid,查找的时候先找索引,然后再根据索引rowid找到块中的行数据 索引组织表,其行数据以索引形式存放,因此找到索引,就等于找到了行数据. -- 堆组织表的数据是散放的,索引和表的数据是分离的 索引组织表的索引和数据是在一起的 -- 堆组织表的存储速度因为不用考虑排序, 所以存储速度会比较快. 但是要查找符合某个条件的记录, 就必须得读取

oracle 索引聚簇表的工作原理

作者:Richard-Lui 一:首先介绍一下索引聚簇表的工作原理:(先创建簇,再在簇里创建索引,创建表时指定列的簇类型) 聚簇是指:如果一组表有一些共同的列,则将这样一组表存储在相同的数据库块中:聚簇还表示把相关的数据存储在同一个块上.利用聚簇,一个块可能包含多个表的数据.概念上就是如果两个或多个表经常做链接操作,那么可以把需要的数据预先存储在一起.聚簇还可以用于单个表,可以按某个列将数据分组存储. 更加简单的说,比如说,EMP表和DEPT表,这两个表存储在不同的segment中,甚至有可能存

关于KMeans的评价及聚簇结果的得到

import numpy as npfrom sklearn.cluster import KMeansfrom sklearn import metricsimport matplotlib.pyplot as plt x1 = np.array([1, 2, 3, 1, 5, 6, 5, 5, 6, 7, 8, 9, 7, 9])x2 = np.array([1, 3, 2, 2, 8, 6, 7, 6, 7, 1, 2, 1, 1, 3])#以下这句话在python3.4版本无效#np.a

oracle聚簇表的理解 (转自:https://blog.csdn.net/gumengkai/article/details/51009345 )

Oracle支持两种类型的聚簇:索引聚簇和哈希聚簇 一.索引聚簇表的原理 聚簇:如果一些表有一些共同的列,则将这样一组表存储在相同的数据块中 聚簇还表示把相关的数据存储在同一个块上.利用聚簇,一个块可能包含多个表的数据. 概念上就是说如果两个表或多个表经常做连接操作,就可以预先把需要的数据也存储在一起. 聚簇还可以用于单个表,可以按某个列将数据分组存储. 简单的说,簇就是一组表,由一组共享相同数据块的多个表组成,将经常一起使用的表组合在一起成簇 就可以提高处理效率. 二.使用方法 建立的顺序:簇

机器学习实战5:k-means聚类:二分k均值聚类+地理位置聚簇实例

k-均值聚类是非监督学习的一种,输入必须指定聚簇中心个数k.k均值是基于相似度的聚类,为没有标签的一簇实例分为一类. 一 经典的k-均值聚类 思路: 1 随机创建k个质心(k必须指定,二维的很容易确定,可视化数据分布,直观确定即可): 2 遍历数据集的每个实例,计算其到每个质心的相似度,这里也就是欧氏距离:把每个实例都分配到距离最近的质心的那一类,用一个二维数组数据结构保存,第一列是最近质心序号,第二列是距离: 3 根据二维数组保存的数据,重新计算每个聚簇新的质心: 4 迭代2 和 3,直到收敛

一个难懂的聚簇分类算法

1.抽取全部图像的surf特征(每个图像的特征行不固定,但是列是固定的70) 2.将图像分为两组,一组训练,一组测试 3.将训练图像全部合并为一个大矩阵,并将矩阵聚簇为30个特征. 4.将每一个图像代入聚簇函数,推测每一个图像属于若干个分组(若不够30个分组,后面补1) 5.每个图像就表示为30个特征向量 6.送入逻辑分类进行分类学习 7.得到训练结果 # -*- coding: utf-8 -*- """ Created on Thu Aug 11 20:51:19 201