索引的聚簇因子分析

简介:

列值的选择性、集簇和柱状图

切记,优化器了解表中列数据的许多重要特征,最显著的是列值的选择性和列的集簇因子。

例如,以下我们看到一个使用列值来形成结果集的查询:

select

   customer_name

from

   customer

where

   customer_state = 'Rhode Island';

在此示例中,选择使用索引还是全表扫描受到搜索到客户比例的影响。如果搜索到的客户的比例非常小,并且数值集簇在数据块中,则对于此查询而言索引扫描可能是最快的执行计划。

许多 Oracle 开发人员对于当他们只检索很少量的行时优化器选择全表扫描而感到困惑,而没有意识到优化器考虑了表中列值的集簇。

Oracle 在 dba_indexes 视图中提供一个名为 clustering_factor 的列,通知优化器关于表的行与索引的同步情况。当集簇因子接近数据块的数量时,表的行与索引同步。

列值的选择性、db_block_size、avg_row_len 以及集合基数全都协同工作,帮助优化器决定是使用索引还是使用全表扫描。如果数据列具有高度的选择性和低的 clustering_factor,则索引扫描通常是最快的执行方法(参见图 2)。

 

         

如果多数 SQL 引用了具有高 clustering_factor、大 db_block_size 和小 avg_row_len 的列,则 DBA 有时会周期性地对表的行进行重排序或使用单表集簇来维持行的顺序。这种方法将所有相邻的行放置在同一数据块中,消除了全表扫描,使查询速度的增加高达 30 倍

相反,高 clustering_factor 的数值达到表中的行数 (num_rows),表明这些行的顺序与索引中的顺序不同,索引范围扫描将会需要额外的 I/O。由于 clustering_factor 达到表中的行数,这些行与索引不同步

但是,即使列具有高度的选择性,高 clustering_factor 和小 avg_row_len 也会表示列值在表中随机分布,而获取这些行需要额外的 I/O。在此情况下,索引范围扫描会导致大量不必要的 I/O(参见图 3);全表扫描则会高效得多。

 

         

总而言之,clustering_factor、db_block_size 和 avg_row_len 全都影响优化器有关执行全表扫描或是索引范围扫描的决策,理解优化器如何使用这些统计信息非常重要。

我们已经注意到,每个新版本的优化器都有改进,并且 Oracle Database 10g 提供的最新增强特性在确定执行计划时会考虑外部的影响。Oracle 称此特性为外部成本核算,并包括对 CPU 和 I/O 成本的评估。

以下例子来说明列值的集簇因子对执行计划产生的影响:

1、 搭建环境  

SQL> insert into test select * from emp;

 

14 rows created.

 

Commit complete.   

2、分析表

SQL> analyze table test compute statistics;

 

Table analyzed.

3、查看列值的集簇因子:

select t.table_name,t.NUM_ROWS,t.BLOCKS,t.AVG_ROW_LEN,i.index_name,i.CLUSTERING_FACTOR

from dba_tables t,dba_indexes i

where t.table_name=i.table_name

and t.owner='SCOTT'

and t.table_name='TEST';

 

 

TABLE_NAME   NUM_ROWS     BLOCKS AVG_ROW_LEN INDEX_NAME CLUSTERING_FACTOR

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

TEST            14               1       32      TEST_ENAME              1

4、使用索引列进行查询:

SQL> select * from test where ename='CUUG1';

 

no rows selected

 

 

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=32)

   1    0   TABLE ACCESS (FULL) OF 'TEST' (TABLE) (Cost=2 Card=1 Bytes

          =32)

 

Statistics

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

          1  recursive calls

          0  db block gets

          3  consistent gets

          0  physical reads

          0  redo size

        615  bytes sent via SQL*Net to client

        376  bytes received via SQL*Net from client

          1  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

          0  rows processed

注;这里执行计划采用全表扫描。(如果使用到了索引,那么再往表中插入一遍数据,然后做analyze,此时oracle就会选择全表扫描)

 

5、往test表中插入数据,注意ename列的值都不一样,也就是有很高的选择性。

declare

      V_ENAME test.ename%type;

    BEGIN

      V_ENAME :='CUUG';

      FOR I IN 1..10000 LOOP

      insert into test (empno,ename,job,sal,deptno)

      values (1121,V_ENAME||I,'WORKER',2000,20);

      END LOOP;

      COMMIT;

    END;

   

6、然后使用索引列进行查询:

SQL> select * from test where ename='CUUG1';

 

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO

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

      1121 CUUG1      WORKER                               2000                    20

 

 

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=32)

   1    0   TABLE ACCESS (FULL) OF 'TEST' (TABLE) (Cost=2 Card=1 Bytes

          =32)

Statistics

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

          1  recursive calls

          0  db block gets

         51  consistent gets

          0  physical reads

          0  redo size

        795  bytes sent via SQL*Net to client

        511  bytes received via SQL*Net from client

          2  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

          1  rows processed

注:这里还是采用了全表扫描的执行计划,按道理列的选择性很高,AVG_ROW_LEN的值也很小,为什么没有采用索引能,一个关键的原因就是集簇因子。

因为test表曾经分析过,在dba_indexes中保留了列值的集簇因子,导致执行计划选择全表扫描。

7、如何让执行计划采用索引,需要对表test再次分析。

 

SQL> analyze table test compute statistics;

 

Table analyzed.

 

 1  select t.table_name,t.NUM_ROWS,t.BLOCKS,t.AVG_ROW_LEN,i.index_name,i.CLUSTERING_FACTOR

  2  from dba_tables t,dba_indexes i

  3  where t.table_name=i.table_name

  4  and t.owner='SCOTT'

  5* and t.table_name='TEST'

SQL> /

 

TABLE_NAME                       NUM_ROWS     BLOCKS AVG_ROW_LEN INDEX_NAME                     CLUSTERING_FACTOR

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

TEST                                10014         47          32 TEST_ENAME                                  1920

注:这里的集簇因子的值变了。

 

8、再次执行查询:

SQL> select * from test where ename='CUUG1';

 

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO

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

      1121 CUUG1      WORKER                               2000                    20

 

 

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=29)

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (TABLE) (Cost=2 Ca

          rd=1 Bytes=29)

 

   2    1     INDEX (RANGE SCAN) OF 'TEST_ENAME' (INDEX) (Cost=1 Card=

          1)

 

Statistics

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

          1  recursive calls

          0  db block gets

          4  consistent gets

          0  physical reads

          0  redo size

        799  bytes sent via SQL*Net to client

        511  bytes received via SQL*Net from client

          2  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

          1  rows processed

注:发现这次执行计划选择了索引。

 

许多 Oracle 开发人员对于当他们只检索很少量的行时优化器选择全表扫描而感到困惑,而没有意识到优化器考虑了表中列值的集簇










本文转自 客居天涯 51CTO博客,原文链接:http://blog.51cto.com/tiany/815217,如需转载请自行联系原作者
目录
相关文章
|
SQL 关系型数据库 MySQL
mysql索引(七)唯一索引
唯一索引(UNIQUE):与"普通索引"类似,不同的就是:索引列的值必须唯一,但允许有空值。
516 0
mysql索引(七)唯一索引
|
存储 关系型数据库 MySQL
为什么MySQL索引使用B+树而不用hash表和B树
支持范围查询:B+树索引在数据结构上有序排列,可以有效支持范围查询,例如大于、小于、区间查询等操作。而哈希表无法支持范围查询,只能进行精确查找,而B树在范围查询操作时性能相对较低。
347 0
|
存储 数据库 索引
聚簇索引什么是非聚簇
聚簇索引和非聚簇索引是数据库中常见的两种索引类型,它们在索引数据的组织方式和存储结构上有所不同。下面我将详细介绍聚簇索引和非聚簇索引的概念、特点和使用场景。
87 0
|
数据库 索引
索引是越多越好嘛? 什么样的字段需要建索引
索引的作用是加快数据库的查询速度,但并不是索引越多越好。过多的索引会增加数据库的存储空间和维护成本,并且在写操作时可能会降低性能。
239 0
|
SQL 关系型数据库 MySQL
表索引——多列索引
前言 多列索引,是指在创建索引时所关联的字段不是一个字段,而是多个字段,虽然可以通过所关联的字段进行查询,但是只有查询条件中使用了所关联字段中的第一个字段,多列索引才会被使用。
|
存储 算法 搜索推荐
【21天算法学习】索引查找
【21天算法学习】索引查找
84 0
|
存储 搜索推荐 数据库
查找-之线性索引查找
针对场景: 博客网站论坛的帖子回复、服务器日志记录 数据量大,每条记录无法做到有序排列记录
94 0
查找-之线性索引查找
|
存储 算法 索引
经典算法之索引查找
经典算法之索引查找
|
存储 算法 C++
查找算法——索引查找
查找算法——索引查找
212 0
查找算法——索引查找
|
存储 NoSQL 关系型数据库
深入理解MySQL索引-为什么采用B+树结构?
深入理解MySQL索引-为什么采用B+树结构?
128 0