整理之前的优化案例,觉得下面这个应该是开发很难发现也会很困惑的一个低效SQL。
看下面这个SQL。你看到这个SQL会不会感觉很正常。其实我刚看到也觉得正常得不得了。但是测试后它确实效率很低。
select test1.object_id, test1.object_name, test1.owner, test1.object_type
from test1
inner join (select test1.object_id as object_id1,
test2.object_id as object_id2,
test3.object_id as object_id3,
test1.object_name as object_name1
from test1, test2, test3
where test1.object_id = test2.object_id
and test1.object_id = test3.object_id
and test2.object_id = test3.object_id) temp
on test1.object_id = temp.object_id1;
测试数据:
create table test1 as select object_id,object_name,owner,object_type from dba_objects;--13433行
create table test2 as select * from test1;--13433行
create table test3 as select * from test1;--13433行
create index i_test1_id on test1(object_id);
analyze table test1 compute statistics for table for all indexes for all indexed columns;
analyze table test2 compute statistics for table;
analyze table test3 compute statistics for table;
原始SQL:
SQL> select test1.object_id, test1.object_name, test1.owner, test1.object_type
2 from test1
3 inner join (select test1.object_id as object_id1,
4 test2.object_id as object_id2,
5 test3.object_id as object_id3,
6 test1.object_name as object_name1
7 from test1, test2, test3
8 where test1.object_id = test2.object_id
9 and test1.object_id = test3.object_id
10 and test2.object_id = test3.object_id) temp
11 on test1.object_id = temp.object_id1;
已选择13433行。
已用时间:  00: 00: 00.41
执行计划
----------------------------------------------------------
Plan hash value: 3055531907
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 68 | 62 (4)| 00:00:01 |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 1 | 68 | 62 (4)| 00:00:01 |
|* 3 | HASH JOIN | | 1 | 30 | 60 (4)| 00:00:01 |
| 4 | TABLE ACCESS FULL | TEST3 | 13433 | 170K| 24 (0)| 00:00:01 |
|* 5 | HASH JOIN | | 13433 | 223K| 35 (3)| 00:00:01 |
| 6 | INDEX FAST FULL SCAN | I_TEST1_ID | 13433 | 53732 | 10 (0)| 00:00:01 |
| 7 | TABLE ACCESS FULL | TEST2 | 13433 | 170K| 24 (0)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | I_TEST1_ID | 1 | | 1 (0)| 00:00:01 |
| 9 | TABLE ACCESS BY INDEX ROWID| TEST1 | 1 | 38 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("TEST1"."OBJECT_ID"="TEST3"."OBJECT_ID" AND
"TEST2"."OBJECT_ID"="TEST3"."OBJECT_ID")
5 - access("TEST1"."OBJECT_ID"="TEST2"."OBJECT_ID")
8 - access("TEST1"."OBJECT_ID"="TEST1"."OBJECT_ID")
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
4086 consistent gets
0 physical reads
0 redo size
549707 bytes sent via SQL*Net to client
10260 bytes received via SQL*Net from client
897 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
13433 rows processed
是不是开始困惑了?子查询我三个表数据一模一样,都是用的inner join,按我们造的测试数据都是从dba_objects的,object_id应该也是唯一的。
test1、test2和test3关联结果应该跟三个表的结果集是一样的才对,怎么三个表hash join的结果竟然是1.最后再跟test1进行一次join,优化器很容易就选择了nested loop。
其实这个我困惑,猜想,优化器由test1.object_id = test2.object_id and test1.object_id = test3.object_id,可以推导出test2.object_id=test3.object_id,
但是限制条件中又写了一遍,它倒评估错了。至于啥原理,我也没搞懂。
去掉test2.object_id=test3.object_id限制,再看下执行计划:
SQL> select test1.object_id, test1.object_name, test1.owner, test1.object_type
2 from test1
3 inner join (select test1.object_id as object_id1,
4 test2.object_id as object_id2,
5 test3.object_id as object_id3,
6 test1.object_name as object_name1
7 from test1, test2, test3
8 where test1.object_id = test2.object_id
9 and test1.object_id = test3.object_id
10 /*and test2.object_id = test3.object_id*/) temp
11 on test1.object_id = temp.object_id1;
已选择13433行。
已用时间:  00: 00: 00.36
执行计划
----------------------------------------------------------
Plan hash value: 144638806
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 13433 | 892K| 84 (3)| 00:00:02 |
|* 1 | HASH JOIN | | 13433 | 892K| 84 (3)| 00:00:02 |
| 2 | TABLE ACCESS FULL | TEST3 | 13433 | 170K| 24 (0)| 00:00:01 |
|* 3 | HASH JOIN | | 13433 | 721K| 60 (4)| 00:00:01 |
| 4 | TABLE ACCESS FULL | TEST2 | 13433 | 170K| 24 (0)| 00:00:01 |
|* 5 | HASH JOIN | | 13433 | 550K| 35 (3)| 00:00:01 |
| 6 | INDEX FAST FULL SCAN| I_TEST1_ID | 13433 | 53732 | 10 (0)| 00:00:01 |
| 7 | TABLE ACCESS FULL | TEST1 | 13433 | 498K| 24 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("TEST1"."OBJECT_ID"="TEST3"."OBJECT_ID")
3 - access("TEST1"."OBJECT_ID"="TEST2"."OBJECT_ID")
5 - access("TEST1"."OBJECT_ID"="TEST1"."OBJECT_ID")
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
1161 consistent gets
0 physical reads
0 redo size
549707 bytes sent via SQL*Net to client
10260 bytes received via SQL*Net from client
897 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
13433 rows processed
这次评估是没错的,外部的test1和三个表关联的结果是一样的,再走hash join也是理所当然的。
这个案例,不是条件写得越多越好。开发可能觉得,把能写的条件都写进去,可是优化器的评估却出乎意料。  
至于优化器评估原理,还没搞懂:(
 

一个令人困惑的低效SQL的更多相关文章

  1. python logging模块可能会令人困惑的地方

    python logging模块主要是python提供的通用日志系统,使用的方法其实挺简单的,这块就不多介绍.下面主要会讲到在使用python logging模块的时候,涉及到多个python文件的调 ...

  2. 如何找出MySQL数据库中的低效SQL语句

    面对业务的迅猛发展,DBA的一项重要工作就是及时发现数据库中的低效SQL语句,有的可以立刻着手解决(比如缺少合适的索引),有的需要尽快反馈给开发人员进行修改. MySQL数据库有几个配置选项可以帮助我 ...

  3. Java安全编码:糟糕的在线建议和令人困惑的APIs

    对于程序员和软件开发人员来说,网络论坛提供了一个交流知识和寻找具体编码难题答案的好地方.遗憾的是,他们并不总是准确信息的来源. 弗吉尼亚理工大学的一组研究人员分析了数百篇关于Stack Overflo ...

  4. 如果一条SQL语句太长,我们可以通过回车键来创建一个新行来编写SQL语句,SQL语句的命令结束符为分号(;)。

    1.如果一条SQL语句太长,我们可以通过回车键来创建一个新行来编写SQL语句,SQL语句的命令结束符为分号(;). 2.select查询的多个字段之间要用逗号“,”分割,如果查询涉及多个表,那多个表之 ...

  5. PLSQL_低效SQL的识别和查询汇总(案例)

    2014-12-18 Created By BaoXinjian

  6. Julie D. Saba:儿童肿瘤学是一个令人惊奇的领域

    编者按 作为一名儿童肿瘤学家,工作中充满了挑战与机遇.近几十年来,世界各地的儿童肿瘤的发病率呈持续上升的趋势.许多人认为这不仅是由于诊断水平的提高,而且是因为儿童肿瘤的潜在风险也确实在增加.据英国儿童 ...

  7. 一个看似很简单的SQL却难倒了很多人

    一个选课表,有学生id,课程id,老师id,要求选出同时选了语文和数学的学生 USE [tempschool] GO /****** 对象: Table [dbo].[SelectC] 脚本日期: 0 ...

  8. 通过一个小问题来学习SQL关联查询

    原话题: 是关于一个left join的,没有技术难度,但不想清楚不一定能回答出正确答案来: TabA表有三个字段Id,Col1,Col2 且里面有一条数据1,1,2 TabB表有两个字段Id,Col ...

  9. 一个简单的ORM制作(SQL帮助类)

    一个简单的ORM制作大概需要以下几个类: SQL执行类 CURD操作类 其他酱油类 先从SQL执行类说起,可能会涉及数据库的迁移等问题,所以需要定义一个接口以方便迁移到其他数据库, 事务没提供命名,若 ...

随机推荐

  1. 1、C语言中的函数指针

    一 通常的函数调用 void MyFun(int x); //此处的申明也可写成:void MyFun( int ); int main(int argc, char* argv[]) { MyFun ...

  2. 用keytool生成证书

    1.创建一个证书C:/jdk1.5.0_04/bin>keytool -genkey -alias xahCA -keyalg RSA -keystore dyfCALib输入keystore密 ...

  3. 自定义控件(视图)1期笔记02:View的绘制流程

    1. 引言: 来自源码的3个方法: (1)public final void measure():测量,用来控制控件的大小,final不建议覆写 (2)public void layout():布局, ...

  4. Objective-C /iphone开发基础:协议(protocol)

    protocol协议时为了补充Objective-C 只能单继承的缺陷而增加的一个新功能.Objective-C重所有的方法都是虚方法,所以在oc重也就没有关键字 virtual一说,有了协议可以补充 ...

  5. modelsim 仿真时出现无限迭代(iteration reach limitation)的原因及其解决办法

    modelsim 仿真时出现无限迭代(iteration reach limitation) 出现这种故障的原因:  一般都是代码里出现的组合逻辑无限循环或者组合逻辑A产生signal_A,signa ...

  6. SSH免密码登录设置

    我们使用ssh-keygen在ServerA上生成private和public密钥,将生成的public密钥拷贝到远程机器ServerB上后,就可以使用ssh命令无需密码登录到另外一台机器Server ...

  7. PowerDesigner使用教程 —— 概念数据模型 (转)

    一.概念数据模型概述    概念数据模型也称信息模型,它以实体-联系(Entity-RelationShip,简称E-R)理论为基础,并对这一理论进行了扩充.它从用户的观点出发对信息进行建模,主要用于 ...

  8. 用JQuery编写textarea,input,checkbox,select

    今天学习怎样用JQuery编写一些小的代码,小小的试了一下编写一个textarea,代码如下: <!DOCTYPE HTML> <html lang="en"&g ...

  9. StrHelper

    public class StrHelper { private static string passWord; //加密字符串 /// <summary> /// 判断输入是否数字 // ...

  10. leetcode之Count Complete Tree Nodes

    Given a complete binary tree, count the number of nodes. Definition of a complete binary tree from W ...