`
zotao
  • 浏览: 31812 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

驱动表、为什么不走索引 小实验

阅读更多

两种连接方式,有驱动表的概念(其实应该说是驱动行源更为准确)

-- hash join

-- nested-loop join

 

对于Nested-loop join

适合于小表(几千条,几万条记录)与大表做联接在联接列上有索引。分内表和外表(驱动表),靠近from子句的是内表。

从效率上讲,小表应该作外表,大表应该作内表,即大表查询时走索引。

 

COST= Access cost of A(驱动表) + (access cost of B * number of rows from A)

 

成本计算方法:

设小表100行,大表100000行。

 

两表均有索引:

如果小表在内,大表在外(驱动表)的话,则扫描次数为:

  100000+100000*2 (其中2表示IO次数,一次索引,一次数据)

如果大表在内,小表在外(驱动表)的话,则扫描次数为:

  100+100*2.

 

两表均无索引:

如果小表在内,大表在外的话,则扫描次数为:

  100000+100*100000

如果大表在内,小表在外的话,则扫描次数为:

  100+100000*100

 

注意:如果一个表有索引,一个表没有索引,ORACLE会将没有索引的表作驱动表。如果两个表都有索引

,则外表作驱动表。如果两个都没索引的话,则也是外表作驱动表。

 

基本的执行计划如下所示:

  NESTED LOOPS

           TABLE ACCESS (BY ROWID)  OF  our_outer_table

                   INDEX (..SCAN) OF outer_table_index(….)

           TABLE ACCESS (BY ROWID)  OF  our_inner_table

             INDEX (..SCAN) OF inner_table_index(….)

 

从效率上讲

from B,        --内表,大表

     A                --外表,小表,驱动表

COST = Access cost of A + (access cost of B * number of rows from A)     

 

---------------------------实验(条件要求,小表很小,大表很大,效果更具有可见性)、结论(仅代表个人意见,有不同意见的可以和我讨论)

大表tt1:

CREATE table tt1

as select * from dba_objects;

小表tt2:

CREATE table tt2

as select * from user_objects;

分析表:

select num_rows,blocks,table_name

from user_tables

where table_name in('TT1','TT2');

 

 

1、两表都无索引,大表在内,小表在外

select tt1.object_name,tt2.object_name

from tt1,

     tt2

where tt1.object_id = tt2.object_id;  

 

2、两表都无索引,小表在内,大表在外

select tt1.object_name,tt2.object_name

from tt2,

     tt1

where tt1.object_id = tt2.object_id;  

 

3、两表无索引,使用hint /*+use_nl(tt2)*/

select /*+use_nl(tt2)*/tt1.object_name,tt2.object_name

from tt2,

     tt1

where tt1.object_id = tt2.object_id; 

 

执行计划:

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

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

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

|   0 | SELECT STATEMENT   |      |    84 |  4032 |   162   (2)| 00:00:02 |

|*  1 |  HASH JOIN         |      |    84 |  4032 |   162   (2)| 00:00:02 |

|   2 |   TABLE ACCESS FULL| TT2  |    86 |  1548 |     3   (0)| 00:00:01 |

|   3 |   TABLE ACCESS FULL| TT1  | 49863 |  1460K|   158   (2)| 00:00:02 |

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

 

结论:

        在没有索引的情况下:

        -- hash join的cost更小,优化器自动选择hash join

        -- 优化器自动选择小表做驱动表

        -- hints也不能改变连接方式

 

 

create index tt1_ind on tt1(object_id);

4、大表有索引,小表无索引,大表在内,小表在外

select tt1.object_name,tt2.object_name

from tt2,

     tt1

where tt1.object_id = tt2.object_id; 

5、大表有索引,小表无索引,小表在内,大表在外

select tt1.object_name,tt2.object_name

from tt1,

     tt2

where tt1.object_id = tt2.object_id; 

 

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

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

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

|   0 | SELECT STATEMENT            |         |   673 | 32304 |   950   (1)| 00:00:12 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TT1     |     8 |   240 |    11   (0)| 00:00:01 |

|   2 |   NESTED LOOPS              |         |   673 | 32304 |   950   (1)| 00:00:12 |

|   3 |    TABLE ACCESS FULL        | TT2     |    86 |  1548 |     3   (0)| 00:00:01 |

|*  4 |    INDEX RANGE SCAN         | TT1_IND |     8 |       |     2   (0)| 00:00:01 |

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

 

结论:

        大表有索引:

        -- 在大表够大的情况下,优化器采用了NL的连接方式

        -- 驱动表的选择与内外没有关系,自动选择小的行源做为驱动表

 

drop index tt1_ind

create index tt2_ind on tt2(object_id);

6、小表有索引,大表无索引,小表在内,大表在外

select tt1.object_name,tt2.object_name

from tt1,

     tt2

where tt1.object_id = tt2.object_id; 

 

7、小表有索引,大表无索引,小表在内,大表在外,加hints

select /*+use_nl(tt1)*/*tt1.object_name,tt2.object_name

from tt1,

     tt2

where tt1.object_id = tt2.object_id; 

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

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

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

|   0 | SELECT STATEMENT   |      |   673 | 32304 |  1230   (2)| 00:00:15 |

|*  1 |  HASH JOIN         |      |   673 | 32304 |  1230   (2)| 00:00:15 |

|   2 |   TABLE ACCESS FULL| TT2  |    86 |  1548 |     3   (0)| 00:00:01 |

|   3 |   TABLE ACCESS FULL| TT1  |   398K|    11M|  1220   (2)| 00:00:15 |

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

结论:

        小表有索引:

        -- 始终不能用大表做驱动表

 

create index tt1_ind on tt1(object_id);

8、大表小表都有索引

select tt1.object_name,tt2.object_name

from tt1,

     tt2

where tt1.object_id = tt2.object_id; 

 

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

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

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

|   0 | SELECT STATEMENT            |         |   673 | 32304 |   950   (1)| 00:00:12 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TT1     |     8 |   240 |    11   (0)| 00:00:01 |

|   2 |   NESTED LOOPS              |         |   673 | 32304 |   950   (1)| 00:00:12 |

|   3 |    TABLE ACCESS FULL        | TT2     |    86 |  1548 |     3   (0)| 00:00:01 |

|*  4 |    INDEX RANGE SCAN         | TT1_IND |     8 |       |     2   (0)| 00:00:01 |

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

结论:

        小表、大表都有索引:

        -- 符合原则,小且做驱动,大表走索引

 

9、两个表一样大,且都有索引

select tt1.object_name,tt2.object_name

from tt1,

     tt2

where tt1.object_id = tt2.object_id;          

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

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

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

|   0 | SELECT STATEMENT   |      | 47358 |  7307K|       |   816   (1)| 00:00:10 |

|*  1 |  HASH JOIN         |      | 47358 |  7307K|  4216K|   816   (1)| 00:00:10 |

|   2 |   TABLE ACCESS FULL| TT2  | 47358 |  3653K|       |   158   (2)| 00:00:02 |

|   3 |   TABLE ACCESS FULL| TT1  | 52860 |  4078K|       |   158   (2)| 00:00:02 |

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

select /*+index(tt2 tt2_ind)*/tt1.object_name,tt2.object_name

from tt1,

     tt2

where tt1.object_id = tt2.object_id;           

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

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

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

|   0 | SELECT STATEMENT             |         | 47358 |  7307K|       |  1898   (1)| 00:00:23 |

|*  1 |  HASH JOIN                   |         | 47358 |  7307K|  4216K|  1898   (1)| 00:00:23 |

|   2 |   TABLE ACCESS BY INDEX ROWID| TT2     | 47358 |  3653K|       |  1240   (1)| 00:00:15 |

|   3 |    INDEX FULL SCAN           | TT2_IND | 47358 |       |       |   124   (2)| 00:00:02 |

|   4 |   TABLE ACCESS FULL          | TT1     | 52860 |  4078K|       |   158   (2)| 00:00:02 |

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

 

结论:

        --两个表一样大,无论用哪个来做驱动表,cost都会很高。

        --优化器自动选择hash join

        --如果要走索引,显然会让cost值增大(因为每一条记录,都要先用索引获得rowid,再回表。)

 

************************************************************************************************************************

 

set linesize 200 pagesize 1000

explain plan for

select /*+index(tt2 tt2_ind)*/tt1.object_name,tt2.object_name

from tt1,

     tt2

where tt1.object_id = tt2.object_id;    

select * from table(dbms_xplan.display());

分享到:
评论

相关推荐

    《数据库系统原理》课程实验指导书'.doc

    在这个实验中,学生将学习SQL的核心语法,包括创建数据库表、定义数据类型、约束和索引等DDL语句。同时,他们还会掌握DML,如插入、更新和删除数据,这是数据库日常操作的关键技能。实验目的在于让学生熟悉SQL语言,...

    湖南大学数据结构链表实验1.zip

    然而,链表的缺点是访问元素的速度较慢,因为不能直接通过索引来定位,而是需要遍历。 在实验中,你可能会遇到以下关键知识点: 1. 链表的定义:理解链表的基本结构,包括头节点、尾节点和指向下一个节点的指针。 2...

    数据库实验 - 实验五 数据完整性控制

    实体完整性规定,主键值不能为空,且必须是唯一的,以确保每个实体(即表中的每一行)都能被准确地识别。 2. 参照完整性:这涉及到表之间的关系。如果一个表中的字段引用了另一个表的主键,那么这个字段必须遵循...

    实验训练2:数据查询操作.docx

    例如,实验中提到查询商品名称为“挡风玻璃”的商品信息,这可以通过SELECT语句结合WHERE子句实现,从商品表中选取符合条件的数据。 多条件查询则是结合多个查询条件进行筛选,如查询所有促销且价格小于1000的商品...

    广州大学数据库原理实验报告.zip

    数据库原理是计算机科学中的核心课程之一,特别是在信息技术和数据驱动的时代背景下,掌握数据库技术显得尤为重要。这份"广州大学数据库原理实验报告"包含了三个主要部分:SQL语言的学习、数据库管理和数据库系统...

    数据库 实验 华科

    9. **数据库集成与应用开发**:实验可能包含使用某种编程语言(如Java、Python)与数据库进行交互,实现简单的数据库驱动的应用程序。 10. **实验报告**:实验结束后,学生需编写实验报告,总结所学知识,分析实验...

    数据仓库与OLAP分析实验及实验教案.rar

    数据仓库与在线分析处理(OLAP)是信息技术领域中的关键组成部分,...通过这个实验,你将不仅掌握数据仓库和OLAP的基础知识,还能提升你的数据分析能力和问题解决技巧,为未来在数据驱动的决策环境中工作打下坚实基础。

    实验四 视图、数据控制

    - **执行SQL语句**:在Form1上添加一个按钮Button1,并为其添加点击事件处理函数,在该函数中编写SQL语句以查询数据库中的表或视图,并将结果展示在界面上。 - **验证结果**:更换不同的SQL语句并观察其执行结果,以...

    中科大数据库实验实例

    例如,实验可能包括创建数据库表、定义字段和数据类型,以及设置主键和外键来确保数据的一致性和完整性。 其次,SQL(Structured Query Language)是用于管理和操作数据库的语言。实验可能涉及编写SQL语句来执行...

    广工操作系统实验13级

    3. 文件系统:学习文件的组织结构,如目录、索引节点等,理解文件的读写操作,掌握文件的打开、关闭、读取、写入等基本函数的使用。可能需要实现一个简单的文件系统模拟器。 4. 设备管理:理解I/O控制方式,如中断...

    数据库原理》实验指导书

    实验主要涵盖了数据库、表和索引的创建与管理,通过实际操作提升对数据定义语言的掌握。在这个实验中,学生将使用SQL Server 2008软件创建新的数据库,并运用SQL语句来建立和调整基本表,同时创建和删除索引。 实验...

    东北大学操作系统实验4次

    6. 设备管理:这部分实验可能涉及设备驱动程序的编写,理解中断处理机制,以及I/O控制方式,如DMA(直接存储器访问)和中断驱动I/O。 7. 虚拟化技术:在现代操作系统中,虚拟化技术是非常重要的一部分,学生可能会...

    实验室管理系统

    【实验室管理系统】是一个基于Java Web技术的毕设项目,旨在为高校或研究机构提供一个集实验资源管理、预约管理、人员管理以及数据统计于一体的信息化解决方案。这个系统可以帮助实验室管理员高效地管理和分配实验...

    SQL Server 2005实验指导手册

    实验五至实验六涉及修改表结构和创建删除索引,这些操作直接影响到数据查询性能。实验七至实验九则涉及数据查询,包括基本的SELECT语句、子查询以及带有各种子句的复杂查询,这些都是数据库操作的核心。实验十至实验...

    操作系统实验

    在这个特定的“操作系统实验”压缩包中,包含了一个名为"0904101.doc"的文档,这可能是实验指导书、实验报告模板或者是某个实验的具体说明。 实验一:进程管理 在这一部分,学生会学习到进程的概念,包括进程的状态...

    数据库实验指导实例 适用于初学者

    ### 数据库实验指导实例知识点概览 #### 一、数据库实验目标与要求 - **目标**:本实验指导书旨在...实验不仅强调理论与实践的结合,还注重培养学生的解决问题能力和团队协作精神,为今后从事IT行业打下坚实的基础。

    数据库实验之数据库实验指导书

    实验的第一步通常是数据库设计,这包括需求分析、概念设计(ER图)、逻辑设计(创建表结构)和物理设计(考虑索引、存储等)。在指导书中,这部分会详细讲解如何进行这些步骤,帮助你理解如何将现实世界的问题转化为...

    图书借阅系统数据库设计实验报告.doc

    实验中涉及实体完整性(如读者号的唯一性)、域完整性(如性别只能为0或1)和参照完整性(如借阅表与读者表、图书表之间的关联)。 六、存储过程和触发器设计 存储过程和触发器用于自动化复杂的数据库操作和执行...

Global site tag (gtag.js) - Google Analytics