Oracle 多表 连接 顺序 与 性能关系 测试
一. 创建表并insert 数据
create table ta (id number,name varchar2(10));
create table tb(id number,job varchar2(10));
begin
for i in 1..1000000 loop
begin
insert into ta values(i,'dave');
commit;
end;
end loop;
end;
begin
for i in 1..1000000 loop
begin
if i<10 then
insert into tb values(i,'boy');
elsif i<20 and i>10 then
insert into tb values(i,'girl');
commit;
end if;
end;
end loop;
end;
二.在没有索引的情况关联ta 和 tb 查询
相关链接:
Oracle Optimizer CBO RBO
http://blog.csdn.net/tianlesoftware/archive/2010/08/19/5824886.aspx
多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
http://blog.csdn.net/tianlesoftware/archive/2010/08/21/5826546.aspx
Oracle Hint
http://blog.csdn.net/tianlesoftware/archive/2010/08/23/5833020.aspx
2.1 optimizer选择 CBO(10g 默认)
--ta 在前
select ta.id, ta.name,tb.job from ta,tb where ta.id=tb.id;
select ta.id, ta.name,tb.job from tb,ta where ta.id=tb.id;
两条SQL 执行计划是一样的, ta和tb 的顺序没有影响。
因为ta和tb 的记录相差较大,ta是100万,tb 只有20条。 所以这里CBO 选择使用Hash Join。
CBO 选择2个表中记录较小的表tb,将其数据放入内存,对Join key构造hash 表,然后去扫描大表ta。 找出与散列表匹配的行。
2.2 对ta和tb 的ID 建b-tree 索引后在查看
--建索引
create index idx_ta_id on ta(id);
create index idx_tb_id on tb(id);
--tb 在前
select ta.id, ta.name,tb.job from tb,ta where ta.id=tb.id;
--ta 在前
select ta.id, ta.name,tb.job from ta,tb where ta.id=tb.id;
总结:
执行计划还是一样,不同的是表之间的关联模式发生的改变,从Hash Join 变成了Nested Loops。
Nested loop一般用在连接的表中有索引,并且索引选择性较好的时候. 在我们这个示例中,CBO 选择把返回结果集较小的表tb 作为outer table,CBO 下,默认把outer table 作为驱动表,然后用outer table 的每一行与inner table(我们这里是ta)进行Join,去匹配结果集。 由此可见,在tb(inner table) 有索引的情况,这种匹配就非常快。
这种情况下整个SQL的cost:
cost = outer access cost + (inner access cost * outer cardinality)
从某种角度上看,可以把Nested loop 看成2层for 循环。
2.3 使用RBO 查看
在10g里,optimizer 默认已经使用CBO了,如果我们想使用RBO, 只能通过Hint 来实现。
-- ta 在前
select /*+rule*/ta.id, ta.name,tb.job from ta,tb where ta.id=tb.id;
SYS@anqing2(rac2)> select /*+rule*/ta.id, ta.name,tb.job from ta,tb where ta.id<100 and ta.id=tb.id;
Elapsed: 00:00:00.00
-- 注意这个SQL里,我们加了ta.id<100 的条件
Execution Plan
----------------------------------------------------------
Plan hash value: 3943212106
---------------------------------------------------
| Id | Operation | Name |
---------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | TABLE ACCESS BY INDEX ROWID | TB |
| 2 | NESTED LOOPS | |
| 3 | TABLE ACCESS BY INDEX ROWID| TA |
|* 4 | INDEX RANGE SCAN | IDX_TA_ID |
|* 5 | INDEX RANGE SCAN | IDX_TB_ID |
---------------------------------------------------
-- 当我们加上条件之后,就先走ta了,而不是tb。 因为先走ta,用ta的限制条件过滤掉一部分结果,这样剩下的匹配工作就会减少。
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("TA"."ID"<100)
5 - access("TA"."ID"="TB"."ID")
Note
-----
- rule based optimizer used (consider using cbo)
--tb 在前
select /*+rule*/ta.id, ta.name,tb.job from tb,ta where ta.id=tb.id;
总结:
这2个就区别很明显。 因为Oracle对sql的解析是从后向前的。 那么当先遇到tb时,那么会对tb进行全表扫描,然后用这个结果匹配ta。因为ta有索引,所以通过索引去匹配。
如果先遇到ta,那么就会对ta进行全表扫描。 因为2个表的差距很大,所以全表扫描的成本也就很大。
所以在RBO 下,大表在前,小表在后。这样就会先遇到小表,后遇到大表。 如果有指定限定的where 条件,会先走限定条件的表。
2.4 drop 索引之后,在走RBO
drop index idx_ta_id;
drop index idx_tb_id;
--ta 在前
select /*+rule*/ta.id, ta.name,tb.job from ta,tb where ta.id=tb.id;
--tb 在前
select /*+rule*/ta.id, ta.name,tb.job from tb,ta where ta.id=tb.id;
总结:
这里选择了Sort Merge Join 来连接2张表。Sort Merge join 用在没有索引,并且数据已经排序的情况.
我们表中的记录是按照顺序插叙的,所以符合这个条件。 SQL 的解析还是按照从后往前,所以这里ta和tb 在前先扫描的顺序不一样,不过都是全表扫描。 效率都不高。
2.5 引深一个问题:使用 字段名 代替 *
* 能方便很多,但在ORACLE解析的过程中, 会通过查询数据字典,会将’*’ 依次转换成所有的列名,这就需要耗费更多的时间. 从而降低了效率。
SYS@anqing2(rac2)> set timing on
SYS@anqing2(rac2)> select * from ta where rownum=1;
ID NAME
---------- ----------
1 dave
Elapsed: 00:00:00.03
SYS@anqing2(rac2)> desc ta
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER
NAME VARCHAR2(10)
SYS@anqing2(rac2)> select id,name from ta where rownum=1;
ID NAME
---------- ----------
1 dave
Elapsed: 00:00:00.02
时间已经缩短。 但不明显,用Toad 来查看一下:
写全字段,执行时间是161 毫秒,用* 是561毫秒。 差距很明显。
查看一下他们的执行计划:
SYS@anqing2(rac2)> select * from ta where rownum=1;
Elapsed: 00:00:00.00
Execution Plan
----------------------------------------------------------
Plan hash value: 761731071
---------------------------------------------------------------------------
| id | operation | name | rows | bytes | cost (%cpu)| time |
---------------------------------------------------------------------------
| 0 | select statement | | 1 | 20 | 7 (72)| 00:00:01 |
|* 1 | count stopkey | | | | | |
| 2 | table access full| ta | 890k| 16m| 7 (72)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM=1)
Note
-----
- dynamic sampling used for this statement
SYS@anqing2(rac2)> select id,name from ta where rownum=1;
Elapsed: 00:00:00.00
Execution Plan
----------------------------------------------------------
Plan hash value: 761731071
---------------------------------------------------------------------------
| id | operation | name | rows | bytes | cost (%cpu)| time |
---------------------------------------------------------------------------
| 0 | select statement | | 1 | 20 | 7 (72)| 00:00:01 |
|* 1 | count stopkey | | | | | |
| 2 | table access full| ta | 890k| 16m| 7 (72)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM=1)
Note
-----
- dynamic sampling used for this statement
注意:
使用 * 和 写全字段名,他们的执行计划是一样的,但是执行时间不一样。
-------------------------------------------------------------------------------------------------------
Blog: http://blog.csdn.net/tianlesoftware
Email: dvd.dba@gmail.com
DBA1 群:62697716(满); DBA2 群:62697977(满) DBA3 群:62697850(满)
DBA 超级群:63306533(满); DBA4 群: 83829929 DBA5群: 142216823
DBA6 群:158654907 聊天 群:40132017 聊天2群:69087192
--加群需要在备注说明Oracle表空间和数据文件的关系,否则拒绝申请
转载于:https://www.cnblogs.com/zlja/archive/2011/06/16/2449636.html
Oracle 多表 连接 顺序 与 性能关系 测试相关推荐
- oracle 内部表连接方式,ORACLE 表连接方式
一表的连接 表的连接是指在一个SQL语句中通过表与表之间的关联,从一个或多个表检索出相关的数据.连接是通过SQL语句中FROM从句的多个表名,以及WHERE从句里定义的表之间的连接条件来实现的.如果一 ...
- oracle 内部表连接方式,oracle表连接方式
ORACLE表连接方式及常见用法(二) /2010-12-22 13:30:13 /个人分类: 一 引言 数据仓库是目前已知的比较成熟和被广泛采用的解决方案,用于整合电信运营内部所有分散的原始业务数据 ...
- 详解oracle多种表连接方式,详解Oracle多种表连接方式
ORACLE 多表连接与子查询 连接的类型 Oracle8i之前的表连接: 等值连接(Equijoin) 非等值连接(Non-Equijoin) 外连接(Outer join):-->左外连接- ...
- Oracle数据库表连接查询并分页SQL语句提示未明确定义列
Oracle数据库表连接查询并分页SQL语句提示未明确定义列 两张表中的字段: t_product t_category product_id category_id product_name cat ...
- oracle中笛卡尔积怎么用,Oracle的表连接方法(四)笛卡尔积
Oracle表连接方法有四种: ● 排序合并连接(Sort Merge Join) ● 嵌套循环连接(Nested Loops Join) ● 哈希连接(Hash Join) ● 笛卡尔积(Carte ...
- Oracle多表连接查询
多个表之间关系:一对多|(多对一) 多对多 一对一 3种 关系的完整性约束:实体完整性.参照完整性.用于定义的完整性. 必须满足实体完整性和参照完整性. 实体完整性:规定了字段|属性的约束 参照完整 ...
- Oracle表连接深入浅出
表的连接 表的连接是指在一个SQL语句中通过表与表之间的关联,从一个或多个表检索出相关的数据.如果一个SQL语句的关联表超过两个, 那么连接的顺序如何呢?ORACLE首先连接其中的两个表,产生一个结果 ...
- oracle连表图解,oracle 表连接方式解析
一.表的连接 表的连接是指在一个SQL语句中通过表与表之间的关联,从一个或多个表检索出相关的数据.连接是通过SQL语句中FROM从句的多个表名,以及WHERE从句里定义的表之间的连接条件来实现的.如果 ...
- oracle表连接分析
一引言 数据仓库技术是目前已知的比较成熟和被广泛采用的解决方案,用于整和电信运营企业内部所有分散的原始业务数据,并通过便捷有效的数据访问手段,可以支持企业内部不同部门,不同需求,不同层次的用户随时获得 ...
最新文章
- 职场老鸟的焦虑与出路
- OpenStack Rally 质量评估与自动化测试利器
- 一条关于互联网创业公司健康与否的判断法则
- 多媒体技术生态未来的三个关键要素
- Android的Recovery中font_10x10.h字库文件制作
- 漫步者lollipods如何调节音量_漫步者MF5扩音器体验:老师值得入手
- 恩智浦NXP I.MX6ULL芯片介绍下载官网资料
- ASP.NET Core 2.1 : 图解路由(2.1 or earler)
- WIN7系统一个盘分多个盘的方法
- php页面怎么改造mip,WordPress MIP 改造之 a 标签替换为 mip-link 跳转链接
- “恩智浦”杯智能车竞赛总结
- linux 查看内存大小命令,Linux查看命令:CPU型号,内存大小,硬盘空间
- 如何公众号运营好一个公众号
- Passenger简介
- 中国古代数学家张丘建在他的《算经》中提出了著名的“百钱买百鸡问题”:鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一,百钱买百鸡,问翁、母、雏各几何?
- [含lw+源码等]javaweb银行柜员业务绩效考核系统
- VB全局HOOK写游戏盗号木马
- 如何计算 NP(natural product likeness)和 BCT(Bertz complexity )?
- Python基础篇5:输入两个数,求它们的和、差、积、商、余数
- Java学习-标准描述类的写法
热门文章
- hexo github搭建博客常用的命令
- 为企业提供本地销售人员的Universal Avenue获1000万美元A轮融资
- BZOJ 1087 [SCOI2005]互不侵犯King ——状压DP
- Linux日志文件总管——logrotate
- static方法不能直接访问类内的非static变量和不能调用this,super语句分析
- juc线程池原理(六):jdk线程池中的设计模式
- SEO网站标题怎么优化
- WCF和webservice的区别
- PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilder
- 学成在线--20.新增课程(最后完善)