两种连接方式,有驱动表的概念(其实应该说是驱动行源更为准确)
-- 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());
分享到:
相关推荐
在这个实验中,学生将学习SQL的核心语法,包括创建数据库表、定义数据类型、约束和索引等DDL语句。同时,他们还会掌握DML,如插入、更新和删除数据,这是数据库日常操作的关键技能。实验目的在于让学生熟悉SQL语言,...
然而,链表的缺点是访问元素的速度较慢,因为不能直接通过索引来定位,而是需要遍历。 在实验中,你可能会遇到以下关键知识点: 1. 链表的定义:理解链表的基本结构,包括头节点、尾节点和指向下一个节点的指针。 2...
实体完整性规定,主键值不能为空,且必须是唯一的,以确保每个实体(即表中的每一行)都能被准确地识别。 2. 参照完整性:这涉及到表之间的关系。如果一个表中的字段引用了另一个表的主键,那么这个字段必须遵循...
例如,实验中提到查询商品名称为“挡风玻璃”的商品信息,这可以通过SELECT语句结合WHERE子句实现,从商品表中选取符合条件的数据。 多条件查询则是结合多个查询条件进行筛选,如查询所有促销且价格小于1000的商品...
数据库原理是计算机科学中的核心课程之一,特别是在信息技术和数据驱动的时代背景下,掌握数据库技术显得尤为重要。这份"广州大学数据库原理实验报告"包含了三个主要部分:SQL语言的学习、数据库管理和数据库系统...
9. **数据库集成与应用开发**:实验可能包含使用某种编程语言(如Java、Python)与数据库进行交互,实现简单的数据库驱动的应用程序。 10. **实验报告**:实验结束后,学生需编写实验报告,总结所学知识,分析实验...
数据仓库与在线分析处理(OLAP)是信息技术领域中的关键组成部分,...通过这个实验,你将不仅掌握数据仓库和OLAP的基础知识,还能提升你的数据分析能力和问题解决技巧,为未来在数据驱动的决策环境中工作打下坚实基础。
- **执行SQL语句**:在Form1上添加一个按钮Button1,并为其添加点击事件处理函数,在该函数中编写SQL语句以查询数据库中的表或视图,并将结果展示在界面上。 - **验证结果**:更换不同的SQL语句并观察其执行结果,以...
例如,实验可能包括创建数据库表、定义字段和数据类型,以及设置主键和外键来确保数据的一致性和完整性。 其次,SQL(Structured Query Language)是用于管理和操作数据库的语言。实验可能涉及编写SQL语句来执行...
3. 文件系统:学习文件的组织结构,如目录、索引节点等,理解文件的读写操作,掌握文件的打开、关闭、读取、写入等基本函数的使用。可能需要实现一个简单的文件系统模拟器。 4. 设备管理:理解I/O控制方式,如中断...
实验主要涵盖了数据库、表和索引的创建与管理,通过实际操作提升对数据定义语言的掌握。在这个实验中,学生将使用SQL Server 2008软件创建新的数据库,并运用SQL语句来建立和调整基本表,同时创建和删除索引。 实验...
6. 设备管理:这部分实验可能涉及设备驱动程序的编写,理解中断处理机制,以及I/O控制方式,如DMA(直接存储器访问)和中断驱动I/O。 7. 虚拟化技术:在现代操作系统中,虚拟化技术是非常重要的一部分,学生可能会...
【实验室管理系统】是一个基于Java Web技术的毕设项目,旨在为高校或研究机构提供一个集实验资源管理、预约管理、人员管理以及数据统计于一体的信息化解决方案。这个系统可以帮助实验室管理员高效地管理和分配实验...
实验五至实验六涉及修改表结构和创建删除索引,这些操作直接影响到数据查询性能。实验七至实验九则涉及数据查询,包括基本的SELECT语句、子查询以及带有各种子句的复杂查询,这些都是数据库操作的核心。实验十至实验...
在这个特定的“操作系统实验”压缩包中,包含了一个名为"0904101.doc"的文档,这可能是实验指导书、实验报告模板或者是某个实验的具体说明。 实验一:进程管理 在这一部分,学生会学习到进程的概念,包括进程的状态...
### 数据库实验指导实例知识点概览 #### 一、数据库实验目标与要求 - **目标**:本实验指导书旨在...实验不仅强调理论与实践的结合,还注重培养学生的解决问题能力和团队协作精神,为今后从事IT行业打下坚实的基础。
实验的第一步通常是数据库设计,这包括需求分析、概念设计(ER图)、逻辑设计(创建表结构)和物理设计(考虑索引、存储等)。在指导书中,这部分会详细讲解如何进行这些步骤,帮助你理解如何将现实世界的问题转化为...
实验中涉及实体完整性(如读者号的唯一性)、域完整性(如性别只能为0或1)和参照完整性(如借阅表与读者表、图书表之间的关联)。 六、存储过程和触发器设计 存储过程和触发器用于自动化复杂的数据库操作和执行...