`

索引分析和比较

阅读更多

转自:http://tb.blog.csdn.net/TrackBack.aspx?PostId=1729625

1、各种索引的创建方法
(1)*tree索引
create index indexname on tablename(columnname);

(2)反向索引
create index indexname on tablename(columnname) reverse;

(3)降序索引
create index indexname on tablename(columnname DESC);

(4)位图索引
create BITMAP index indexname on tablename(columnname);

(5)函数索引
create index indexname on tablename(functionname(columnname));

创建索引后要分析才能使用

analyze table test compute statistics  for table for all indexed columns for all indexes;
analyze index test validate structure;
select name,lf_rows from index_stats;用这条语句可以查询保存了多少条索引
analyze index test compute statistics;

从字面理解validate structure 主要在于校验对象的有效性. compute statistics在于统计相关的信息..

查询索引
select index_name,index_type from user_indexes where table_name='TEST';

2、打开autotrace功能
执行$ORACLE_HOME/rdbms/admin/utlxplan.sql和$ORACLE_HOME/sqlplus/admin/plustrce.sql
然后给相关用户授予plustrace角色,然后这些用户就可以使用autotrace功能了

3、无效索引
(1)类型不匹配
create table test(a varchar(2),b number);
insert into test values('1',1);
create index test_index on test(a);
analyze table test compute statistics  for table for all indexed columns for all indexes;
set autotrace on;

类型匹配的情况
select /*+ RULE */ *  from test where a='1';

A           B
-- ----------
1           1


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=HINT: RULE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST'
   2    1     INDEX (RANGE SCAN) OF 'TEST_INDEX' (NON-UNIQUE) 使用了索引


类型不匹配的情况
select /*+ RULE */ *  from test where a=1;


A           B
-- ----------
1           1


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=HINT: RULE
   1    0   TABLE ACCESS (FULL) OF 'TEST' 选择了全表扫描


(2)条件包含函数但没有创建函数索引
alter system set QUERY_REWRITE_ENABLED=true;
alter system set query_rewrite_integrity=enforced;

insert into test values('a',2);
select /*+ RULE */ *  from test where upper(a) = 'A';
A           B
-- ----------
a           2


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=HINT: RULE
   1    0   TABLE ACCESS (FULL) OF 'TEST'   


由于没有创建函数索引,所以选择全表扫描

create index test_index_fun on test(upper(a));
analyze table test compute statistics  for table for all indexed columns for all indexes;

select /*+ RULE */ *  from test where upper(a) = 'A';
A                                                           B
-------------------------------------------------- ----------
a                                                           2
a                                                           3
a                                                           4


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=HINT: RULE
   1    0   TABLE ACCESS (FULL) OF 'TEST'

虽然创建了函数索引,但由于工作于RBO模式,所以函数索引没用,选择了全表扫描

select * from test where upper(a) = 'A';
A                                                           B
-------------------------------------------------- ----------
a                                                           2
a                                                           3
a                                                           4


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=9)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (Cost=2 Card=1 Byt
          es=9)

   2    1     INDEX (RANGE SCAN) OF 'TEST_INDEX_FUN' (NON-UNIQUE) (Cos
          t=1 Card=1)

当函数索引工作于CBO模式下,选择了基于函数的索引,上面创建的索引函数TEST_INDEX_FUN已经用到

(3)符合索引中的前导列没有被作为查询条件
create index test_index_com on test(a,b);
select /*+ RULE */ *  from test where a = '1';
A           B
-- ----------
1           1

前导列a作为了查询条件,但由于之前创建了a的索引,所以使用了TEST_INDEX而没有使用test_index_com
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=HINT: RULE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST'
   2    1     INDEX (RANGE SCAN) OF 'TEST_INDEX' (NON-UNIQUE)


select /*+ RULE */ *  from test where b = '1';

A           B
-- ----------
1           1
2           1
3           1
4           1


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=HINT: RULE
   1    0   TABLE ACCESS (FULL) OF 'TEST'

前导列a没有作为查询条件,所以选择全部扫描


select /*+ RULE */ *  from test where b = '1' and a= '1';

A           B
-- ----------
1           1


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=HINT: RULE
   1    0   INDEX (RANGE SCAN) OF 'TEST_INDEX_COM' (NON-UNIQUE)
前导列a作为了查询条件,使用了索引


(4)CBO模式下选择的行数比例过大,优化器选择全表扫描


declare
       i number;
       j number;
begin
for i in 1 .. 10 loop
for j in 1 .. 10000 loop
insert into test values(to_char(j),i);
end loop;
end loop;
end;
/


declare i number;
begin
for i in 1 .. 100 loop
insert into test values(to_char(i),i);
end loop;
end;
/


SQL> select count(*) from test;

  COUNT(*)
----------
    200000


select  * from test where a = '1';
已选择10000行。


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=27 Card=9333 Bytes=7
          4664)

   1    0   TABLE ACCESS (FULL) OF 'TEST' (Cost=27 Card=9333 Bytes=746
          64)

比例过大,选择全表扫描


select * from test where a = '99';

已选择10行。


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=2 Bytes=16)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (Cost=2 Card=2 Byt
          es=16)

   2    1     INDEX (RANGE SCAN) OF 'TEST_INDEX' (NON-UNIQUE) (Cost=1
          Card=2)


比例小,选择索引


select  /*+ RULE */ * from test where a = '1';

已选择10000行。
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=HINT: RULE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST'
   2    1     INDEX (RANGE SCAN) OF 'TEST_INDEX' (NON-UNIQUE)


如果指定为RBO优化器,肯定就用索引了


(5)在CBO模式下表很久没分析,表的增长明显,优化器采取了全表扫描

(6)索引条件中使用了<>、!=、not\not in、not like等操作符,导致查询不使用索引
先做一个测试在一个表中插入130万条数据,其中不等于1的数据有30万条,以下是几种语句执行的结果
 序号 语句                                                                 时间          代价
 1    select * from test where b<>1;                                       00: 00: 03.04 398
 2    select * from test where b not like 1;                               00: 00: 03.03 398
 3    select * from test where b !=1;                                      00: 00: 03.01 398
 4    select * from test where b not in(1);                                00: 00: 03.00 398
 5    select * from test where b<1 union select * from test where b>1;     00: 00: 03.01 264
 6    select * from test where b<1 union all select * from test where b>1; 00: 00: 02.09 132
 7    select * from test where b<1 or b>1;                                 00: 00: 02.08 96
从以上可以看出最优化的语句是7,在查询过程中使用索引的有5、6、7
所以,如果建立了索引,在语句中尽量不要使用<>、!=、not、not in、not like操作,如果非要使用,请尽量用or和union操作替换


(7)索引对空值的影响

我们首先做一些测试数据:

SQL> create table t(x int, y int);

请注意,这里我对表t做了一个唯一(联合)索引:

SQL> create unique index t_idx on t(x,y);
SQL> insert into t values(1,1);
SQL> insert into t values(1,NULL);
SQL> insert into t values(NULL,1);
SQL> insert into t values(NULL,NULL);
SQL> commit;

下面我们分析一下索引:

SQL> analyze index t_idx validate structure;

SQL> select name,lf_rows from index_stats;


NAME                              LF_ROWS

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

T_IDX                                   3


然后,我们就可以看到,当前的索引中仅仅保存了3行数据。

请注意,上面我们插入并提交了四行数据。

所以,这里就有一个结论:

Oracle的索引不保存该索引包含的列中全部为空的行。
这同时也带来个好处,但当一个表中的某一列大部分为空值,至少90%以上是空值的时候,就可以为该列建立索引。

比如该表为t,该列为x
select * from t where x is null;
此时会选择全表扫描

select * from t where x=1;
此时就会使用索引,而且索引中不保存值为空的行,所以索引中只有10%左右的行,因此在这10%的行中找出x=1的行比在全表中找出x=1的行要快的多


我们继续插入数据,现在再插入几行全部为空的行:

SQL> insert into t values(NULL,NULL);

SQL> insert into t values(NULL,NULL);

我们看到这样的插入,居然没有违反前面我们设定的唯一约束(unique on t(x,y)),

所以,这里我们又得出一个结论:

Oracle认为 NULL<>NULL ,进而 (NULL,NULL)<>(NULL,NULL)

换句话说,Oracle认为空值(NULL)不等于任何值,包括空值也不等于空值。


我们看到下面的插入会违反唯一约束(DEMO.T_IDX),这个很好理解了,因为它不是全部为空的值,即它不是(NULL,NULL),只有全部为空的行才被认为是不同的行:

SQL> insert into t values(1,null);

ORA-00001: 违反唯一约束条件 (DEMO.T_IDX)

SQL> insert into t values(null,1);

ORA-00001: 违反唯一约束条件 (DEMO.T_IDX)

 

SQL>

 

请看下面的例子:

SQL> select x,y,count(*) from t group by x,y;

 

    X        Y   COUNT(*)

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

                        3

             1          1

    1                   1

    1        1          1

Executed in 0.03 seconds

 

SQL> select x,y,count(*) from t where x is null and y is null group by x,y;

 

   X       Y   COUNT(*)

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

                      3

 

Executed in 0.01 seconds

 

SQL>

SQL> select x,y,count(*) from t group by x,y having count(*)>1;

 

     X                    Y   COUNT(*)

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

                                     3

 

Executed in 0.02 seconds

SQL>

可以看见,完全为空的行有三行,这里我们又可以得出一个结论:

oracle在group by子句中认为完全为空的行是相同的行

换句话说,在group by子句中,oracle认为(NULL,NULL)=(NULL,NULL)


SQL> select * from t where x is null;

         X          Y
---------- ----------
                    1

 

 

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=4 Bytes=8)
   1    0   TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=4 Bytes=8)

 

SQL> select * from t where x=1;

         X          Y
---------- ----------
         1          1
         1


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=2 Bytes=4)
   1    0   INDEX (RANGE SCAN) OF 'T_IDX' (UNIQUE) (Cost=1 Card=2 Byte
          s=4)

 

从以上可以看出,在使用IS NULL 和 IS NOT NULL条件的时候,Oracle不使用索引

那么我们如何使用空值的比较条件呢?

首先,尽量不在前导列上使用空值,其次我们在创建表的时候,为每个列都指定为非空约束(NOT NULL),并且在必要的列上使用default值

 

8、不要为所有的列建立索引

我们知道,建立索引是为了提高查询的效率,但是同时也应该注意到,索引增加了对DML操作(insert, update, delete)的代价,而且,一给中的索引如果太多,那么多数的索引是根本不会被使用到的,而另一方面我们维护这些不被使用的所以还要大幅度降低系统的性能。所以,索引不是越多越好,而是要恰到好处的使用。

 

比如说,有些列由于使用了函数,我们要使用已有的索引(如一些复合索引)是不可能的,那么就必须建立单独的函数索引,如果说这个函数索引很少会被应用(仅仅在几个特别的sql中会用到),我们就可以尝试改写查询,而不去建立和维护那个函数索引,例如:

 


1,trunc函数

SQL> select empno,ename,deptno from emp where trunc(hiredate)='2004-01-01';

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   TABLE ACCESS (FULL) OF 'EMP'


将上面的查询转换为:

SQL> select empno,ename,deptno from emp

  2  where hiredate >= to_date('2004-01-01','yyyy-mm-dd')

  3  and hiredate<to_date('2004-01-01','yyyy-mm-dd')+0.999;

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP'

   2    1     INDEX (RANGE SCAN) OF 'EMP_ID3' (NON-UNIQUE)


2,to_char函数

SQL> select empno,ename,deptno from emp

  2  where to_char(hiredate,'yyyy-mm-dd')='2003-09-05';

 
Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   TABLE ACCESS (FULL) OF 'EMP'

 

SQL> select empno,ename,deptno from emp

  2  where hiredate=to_date('2003-09-05','yyyy-mm-dd');

 
Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP'

   2    1     INDEX (RANGE SCAN) OF 'EMP_ID3' (NON-UNIQUE)

 
3,substr函数

SQL> select dname from dept where substr(dname,1,3)='abc';

 
Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   TABLE ACCESS (FULL) OF 'DEPT'

 


SQL>  select dname from dept where dname like 'abc%';

 

Execution Plan

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

   0      SELECT STATEMENT Optimizer=CHOOSE

   1    0   INDEX (RANGE SCAN) OF 'DEPT_ID1' (NON-UNIQUE)

 通常,为了均衡查询的效率和DML的效率,我们要仔细的分析应用,找出来出现频率相对较多、字段内容较少(比如varchar2(1000)就不适合建立索引,而varchar2(10)相对来说就适合建立索引)的列,合理的建立索引,比如有时候我们希望建立复合索引,有时候我们更希望建立单键索引。

分享到:
评论

相关推荐

    DB2索引分析器使用简述

    “db2advis”是一个用于分析和优化数据库中SQL语句执行计划的工具。它可以针对具体的SQL语句或一组SQL语句提供优化建议,包括但不限于创建新的索引、调整现有索引以及建议是否使用Materialized Query Tables (MQTs) ...

    Oracle索引分析与比较

    本篇文章将深入探讨Oracle中的B*Tree索引、反向索引、降序索引、位图索引和函数索引。 1. **B*Tree索引**: - B*Tree索引是Oracle中最常见的索引类型,其结构类似于二叉树,可以高效地处理高基数数据列,即具有...

    oracle索引分析与比较

    4. **位图索引**:位图索引适合于低基数和分析性查询(OLAP),尤其是用于关联少量数据行的情况。它使用位图来表示数据行与索引项的关系,每个位代表一行。对于多列组合索引或选择性较低的列,位图索引能提供高效的...

    MySQL索引分析和优化.pdf

    ### MySQL索引分析与优化详解 #### 一、引言 在现代数据库管理系统中,索引扮演着极其重要的角色。合理的索引设计不仅能显著提升查询性能,还能优化数据的存储结构,进而提高整个系统的响应速度。本文将深入探讨...

    MySQL索引分析及优化.pdf

    "MySQL索引分析及优化" 索引是数据库中提高速度的一个关键因素。如果作为搜索条件的列上已经创建了索引,MySQL无需扫描任何记录即可迅速得到目标记录所在的位置。索引的使用可以大幅度地提高查询速度,减少数据库的...

    MySQL索引分析和优化

    MySQL索引分析和优化是数据库管理中的重要环节,它直接影响到数据查询的速度和数据库的性能。索引可以被看作是数据库中的一种特殊文件,它按照特定的规则组织,允许数据库快速定位到所需的数据行。 首先,我们来看...

    MySQL索引分析和优化[定义].pdf

    因此,合理地设计索引和定期分析其性能是非常重要的。 8. **索引优化**:MySQL提供了`EXPLAIN`关键字,可以帮助分析查询执行计划,了解是否正确使用了索引。通过`EXPLAIN`,可以发现查询是否进行了全表扫描、是否...

    mysql索引分析和优化

    ### MySQL索引分析和优化深度解析 #### 引言 MySQL数据库系统中,索引扮演着至关重要的角色,尤其在大数据量的环境下,其对查询性能的影响不可小觑。索引能够极大地加速数据检索速度,减少数据库服务器的负载,...

    Sqlserver索引分析

    Sqlserver索引分析,Sqlserver索引缺失,Sqlserver索引建议

    Mysql-索引原理分析

    MySQL数据库中的索引是提升查询性能的关键工具,它的工作原理和设计细节对于数据库管理员和开发者来说至关重要。...同时,索引的维护也是数据库管理的重要部分,包括定期分析和优化索引,以确保数据库的高效运行。

    数据库索引设计和优化

    2. 避免索引失效:使用函数、IN操作符、NOT操作符等可能导致索引失效,应尽量让索引列直接参与比较。 3. 选择正确的JOIN策略:了解不同JOIN类型的性能差异,如NLJOIN、HASH JOIN和MERGE JOIN。 五、实际应用中的...

    SQL_Server2005索引碎片分析和解决方法

    ### SQL Server 2005 索引碎片分析与解决方法 #### 一、索引碎片的概念 在SQL Server 2005中,索引是提高查询效率的重要手段之一。然而,随着数据的增删改查操作,索引可能会出现碎片化现象。碎片化的索引会导致...

    SQL Server 索引结构及其使用(聚集索引与非聚集索引)

    在实践中,聚集索引和非聚集索引的使用规则很容易被忽视或不能根据实际情况进行综合分析。例如,主键就是聚集索引是一种误区。虽然 SQL SERVER 默认是在主键上建立聚集索引的,但这并不意味着主键一定是聚集索引。 ...

    Lucene索引数据分析器

    这种可视化方式对于数据分析和问题排查非常有帮助,尤其在处理大量数据时,能够提高工作效率。 在实际开发中,结合如Excel或数据可视化库(如Python的Pandas或JavaScript的D3.js),开发者可以创建交互式报告,...

    histcite(文献索引分析软件) 附使用教程.rar

    5. 结果导出:分析结果可以导出为各种格式,便于进一步的分析和分享。 三、histcite的优势 1. 提高效率:histcite节省了人工查找和整理文献引用关系的时间,使科研工作更加高效。 2. 深度分析:软件提供强大的数据...

    MongoDB学习笔记(六) MongoDB索引用法和效率分析

    MongoDB是一种流行的NoSQL数据库,它的索引机制与传统的关系型数据库类似,旨在提升查询和排序的速度。...同时,定期分析查询性能和索引使用情况,根据需求调整索引策略,也是数据库管理的重要环节。

    数据库非聚集索引 聚集索引 模式 索引

    本文将深入探讨数据库中的非聚集索引、聚集索引以及索引模式的概念,并分析它们之间的区别。 首先,让我们了解一下**非聚集索引**。非聚集索引在数据库中不按照数据的实际物理顺序存储。每个非聚集索引条目包含键值...

Global site tag (gtag.js) - Google Analytics