Oracle 11g Concepts 笔记1:联合索引的创建及注意事项

众所周知,每一位Oracle数据库技术牛人,每一名Oracle DBA在谈到自己的成长历程或者分享学习经验时,都会强调阅读Oracle的官方文档的重要性和必要性。而Oracle提供的官方文档数量之多,范围之广让很多初学者都望而却步,尤其是对于英语基础不好的网友更是头痛不已。其实,就我个人而言,也是经历过诸多痛苦的。事实上,我想但凡每一位认认真真地阅读过官方文档的过来人都或多或少的会有同感。既然Oracle提供给我们的学习文档如此之多,那么我们又该选择哪些文档入手呢?

我的建议是,优先阅读也是最应该阅读 Oracle Database Concepts这本书,因为这本书涵盖了Oracle数据库的全部基本概念,多读此书,收获颇多。记得当初08年的时候,自学Oracle,备考Oracle 10g OCA时,自己坚持着把10g 版本的 Oracle Concepts 10g Release 2前2/3部分反复阅读了几次,得以对Oracle数据库算是有个基本了解。

本系列文章将以笔记的形式记录自己在阅读和学习Oracle 11gR2 Database Concepts 【文档编号为E16508-05】的心得和体会。一方面算是对自己的知识总结和记录,另一方面也希望这一系列的文章能够对广大Oracle数据库技术爱好者带来帮助。当然,如果有理解的不对或者是纰漏之处,还恳请广大网友及时回复给予指正。 好了,废话不再赘述。

Oracle 11gR2 Database Concepts第3章Page 57讲到Indexes and Index-Organized Tables,其中Page 59讲到Composite Indexes。

首先,我们创建测试表,并在该表上创建联合索引:


SQL> conn / as sysdba
Connected.
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 - Production
CORE    11.2.0.1.0      Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production 

SQL> conn hr/hr

Connected.

SQL> create table t(id1 number,id2 number,name varchar2(10));

Table created.

SQL> create index idx_t_id1_id2 on t(id1,id2);

Index created.

SQL> insert into t values(1,1,'oracle');

1 row created.

SQL> insert into t values(2,2,'on');

1 row created.

SQL> insert into t values(3,2,'linux');

1 row created.

SQL> commit;

Commit complete.

SQL> select * from t;

ID1        ID2 NAME

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

1          1 oracle

2          2 on

3          2 linux

然后,查看执行计划1:

SQL> set autot trace exp

SQL> select * from t where id1=1;

Execution Plan

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

Plan hash value: 1660670018

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

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

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

|   0 | SELECT STATEMENT            |               |     1 |    33 |     1   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T             |     1 |    33 |     1   (0)| 00:00:01 |

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

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

Predicate Information (identified by operation id):

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

2 - access("ID1"=1)

Note

-----

- dynamic sampling used for this statement (level=2)

SQL>

发现该语句走索引。

查看执行计划2:

SQL> select * from t where id2=1;

Execution Plan

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

Plan hash value: 1601196873

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

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

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

|   0 | SELECT STATEMENT  |      |     1 |    33 |     3   (0)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| T    |     1 |    33 |     3   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

1 - filter("ID2"=1)

Note

-----

- dynamic sampling used for this statement (level=2)

SQL>

SQL> select * from t where id2=2;

Execution Plan

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

Plan hash value: 1601196873

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

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

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

|   0 | SELECT STATEMENT  |      |     2 |    66 |     3   (0)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| T    |     2 |    66 |     3   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

1 - filter("ID2"=2)

Note

-----

- dynamic sampling used for this statement (level=2)

SQL>

发现该语句走的全表扫描,而没走索引,id2字段上创建了联合索引,为什么不走索引呢?

查看执行计划3:

SQL> select * from t where id1=3 and id2=2;

Execution Plan

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

Plan hash value: 1660670018

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

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

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

|   0 | SELECT STATEMENT            |               |     1 |    33 |     1   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T             |     1 |    33 |     1   (0)| 00:00:01 |

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

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

Predicate Information (identified by operation id):

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

2 - access("ID1"=3 AND "ID2"=2)

Note

-----

- dynamic sampling used for this statement (level=2)

SQL> select * from t where id2=2 and id1=3;

Execution Plan

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

Plan hash value: 1660670018

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

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

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

|   0 | SELECT STATEMENT            |               |     1 |    33 |     1   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T             |     1 |    33 |     1   (0)| 00:00:01 |

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

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

Predicate Information (identified by operation id):

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

2 - access("ID1"=3 AND "ID2"=2)

Note

-----

- dynamic sampling used for this statement (level=2)

SQL>

Where从句中包含联合索引的所有字段时,优化器都会选择走索引,不论是将id1放前还是id2放前。

查看执行计划4:

SQL> select * from t where id1=2 and name='on';

Execution Plan

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

Plan hash value: 1660670018

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

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

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

|   0 | SELECT STATEMENT            |               |     1 |    33 |     1   (0)| 00:00:01 |

|*  1 |  TABLE ACCESS BY INDEX ROWID| T             |     1 |    33 |     1   (0)| 00:00:01 |

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

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

Predicate Information (identified by operation id):

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

1 - filter("NAME"='on')

2 - access("ID1"=2)

Note

-----

- dynamic sampling used for this statement (level=2)

SQL> select * from t where id2=2 and name='on';

Execution Plan

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

Plan hash value: 1601196873

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

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

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

|   0 | SELECT STATEMENT  |      |     1 |    33 |     3   (0)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| T    |     1 |    33 |     3   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

1 - filter("ID2"=2 AND "NAME"='on')

Note

-----

- dynamic sampling used for this statement (level=2)

SQL>

看到,第一条SQL语句(id1=2 and name=’on’)走了索引,而第二条SQL语句(id2=2 and name=’on’)走的却是全表扫描,似乎更奇怪?

最后,我们可以得出以下结论:

1 对于联合索引,在Where限制条件中出现所有被索引的列时,优化器会选择走索引(上述执行计划3);

2 对于联合索引,在Where限制条件中出现联合索引中前导的列,即创建联合索引时前导的列时,优化器会选择走索引(执行计划1,2,4中,凡是有id1作为限制条件时都会走索引,而将id2作为限制条件时均不走索引,而走全表扫描);

3 对于创建联合索引时,应考虑被索引字段的优先顺序,应将经常作为限制条件的字段放在首位;重复值少,即高基数(high-cardinaltiy)的列往前靠,而重复值多的字段往后靠;

4 对于同一张表,可以创建多个不同的联合索引,前提是,被索引的字段的个数、顺序不能一样,否则报错,ORA-01408如:

SQL> create index idx1_t_id1_id2 on t(id1,id2);

create index idx1_t_id1_id2 on t(id1,id2)

*

ERROR at line 1:

ORA-01408: such column list already indexed

SQL> create index idx1_t_id1_id2 on t(id2,id1);

Index created.

SQL>

5 联合索引及前导列的解释:

A composite index, also called a concatenated index,is an index on multiple columns in a table.
A leading portion of an index is a set of one or more columns that were specified first and consecutively in the list of columns in the CREATE INDEX statement that created the index.

Consider this CREATE INDEX statement:

CREATE INDEX comp_ind ON tab1(x, y, z);

These combinations of columns are leading portions of the index: x, xy, and xyz.

These combinations of columns are not leading portions of the index: yz, y, and z.

A SQL statement can use an access path involving a composite index if the statement contains constructs that use a leading portion of the index.

iPod Nano 6入手初体验

经过长达两个多月的等待,终于收到了这份迟来的小礼物,iPod Nano 6 8GB。虽然来的有些迟,甚至因为新加坡那边儿投递的原因差点儿导致与这款小巧却功能强大的MP3失之交臂,但是收到快递包裹的那一刻,还是有一点儿小兴奋的。

话说这个免费礼物的由来,7月份的时候,接到365信息科技大讲堂的邮件邀请,于2011年7月20日参加了甲骨文网上讲座 “最高的数据库性能和快速 100% 的投资回报率”,会后成为众多参与者中的幸运儿。

初入手时,精致而又环保的包装,着实给用户一个完美的体验,尤其是那个设计别有用心的卡片式基本使用说明手册。拆解开来,银白色的机身,延续苹果产品的主打色系。据称,苹果的这款机器投入生产时白黑比是6:1,而市场反应是,消费者的喜好却是白黑比1:6,黑色系的机器颇受消费者的青睐。个人而言,白也好,黑也罢,好用就行,当然更不能颠倒黑白。

接下来,第一件事就是阅读手册,登录苹果官网,获取更多的用户指南。

第二,连接USB接口进行充电,在充电的过程中,顺便安装配置iTunes。这里出了一个小差错,充电大概10分钟左右,误操作断开了iPod Nano,导致充电结束。苹果官方申明初次充电要到2-3小时左右,担心会不会出什么问题,以后电池会不会都充不满?没辙呀,自己是个土包子,从未拥有过苹果的任何产品,使用经验更几乎为零。在此,向各位请教,为什么现在用USB连接线给Nano充电都充不满?是否需要购买iPod 专属充电器?

第三,使用iTunes同步数据,这个应用程序的功能比较强大,就是要注册用户的那个玩意儿比较繁琐,貌似要Visa信用卡号之类的,目前还未注册成功。

第四,Nano的收音机功能很好用,可以迅速搜索当地的所有无线电台。

第五,健身功能很好用,可以记录步行、跑步的数据,并且可以同步到Nike +。

第六,时钟不错,好用。

第七,MP3播放功能和效果自是不用说了,超牛逼。

第八,感谢365信息科技大讲堂,那次会议不仅给予我Oracle相关的知识,还赠送我这个可爱的小礼物。当然还要感谢自己对于Oracle数据库技术的热爱,看来选择从业Oracle DBA还是非常不错的,至少有Nano可以免费玩儿。欢迎Nano网友回复交流用户经验及Oracle数据库相关技术经验,谢谢!

最后,附上邮件确认函一封:

From: Oracle APAC Responses Team <response@oracleevent.com>
Date: Fri, 22 Jul 2011 07:44:40 +0100
Subject: 甲骨文网上讲座: 祝贺你, 您已成为甲骨文网上讲座的iPod Nano幸运儿
To: “3dian14@gmail.com” <3dian14@gmail.com>

Dear黄伟,

谢谢您出席2011 年 7 月 20 日, 星期三的甲骨文网上讲座 “最高的数据库性能和快速 100% 的投资回报率”

您已成为甲骨文网上讲座的iPod Nano幸运儿!

请您确认以下的地址:
厦门火炬高新区软件园二期望海路29#吉联研发大楼, 厦门, 福建 361006, China
(Xiamen Torch Hi-tech Software Park two WangHai 29 # Kyrgyzstan joint
R & D Building, Xiamen, Fujian 361006, China)

我们期待您的答复。

The Oracle Corporation