一个令人困惑的低效SQL
整理之前的优化案例,觉得下面这个应该是开发很难发现也会很困惑的一个低效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的更多相关文章
- python logging模块可能会令人困惑的地方
python logging模块主要是python提供的通用日志系统,使用的方法其实挺简单的,这块就不多介绍.下面主要会讲到在使用python logging模块的时候,涉及到多个python文件的调 ...
- 如何找出MySQL数据库中的低效SQL语句
面对业务的迅猛发展,DBA的一项重要工作就是及时发现数据库中的低效SQL语句,有的可以立刻着手解决(比如缺少合适的索引),有的需要尽快反馈给开发人员进行修改. MySQL数据库有几个配置选项可以帮助我 ...
- Java安全编码:糟糕的在线建议和令人困惑的APIs
对于程序员和软件开发人员来说,网络论坛提供了一个交流知识和寻找具体编码难题答案的好地方.遗憾的是,他们并不总是准确信息的来源. 弗吉尼亚理工大学的一组研究人员分析了数百篇关于Stack Overflo ...
- 如果一条SQL语句太长,我们可以通过回车键来创建一个新行来编写SQL语句,SQL语句的命令结束符为分号(;)。
1.如果一条SQL语句太长,我们可以通过回车键来创建一个新行来编写SQL语句,SQL语句的命令结束符为分号(;). 2.select查询的多个字段之间要用逗号“,”分割,如果查询涉及多个表,那多个表之 ...
- PLSQL_低效SQL的识别和查询汇总(案例)
2014-12-18 Created By BaoXinjian
- Julie D. Saba:儿童肿瘤学是一个令人惊奇的领域
编者按 作为一名儿童肿瘤学家,工作中充满了挑战与机遇.近几十年来,世界各地的儿童肿瘤的发病率呈持续上升的趋势.许多人认为这不仅是由于诊断水平的提高,而且是因为儿童肿瘤的潜在风险也确实在增加.据英国儿童 ...
- 一个看似很简单的SQL却难倒了很多人
一个选课表,有学生id,课程id,老师id,要求选出同时选了语文和数学的学生 USE [tempschool] GO /****** 对象: Table [dbo].[SelectC] 脚本日期: 0 ...
- 通过一个小问题来学习SQL关联查询
原话题: 是关于一个left join的,没有技术难度,但不想清楚不一定能回答出正确答案来: TabA表有三个字段Id,Col1,Col2 且里面有一条数据1,1,2 TabB表有两个字段Id,Col ...
- 一个简单的ORM制作(SQL帮助类)
一个简单的ORM制作大概需要以下几个类: SQL执行类 CURD操作类 其他酱油类 先从SQL执行类说起,可能会涉及数据库的迁移等问题,所以需要定义一个接口以方便迁移到其他数据库, 事务没提供命名,若 ...
随机推荐
- TCP/IP协议原理与应用笔记04:子网掩码
1. 子网掩码 是IP 参照物:分网段用的! 比如 192.168.0.1 和192.168.0.2(1).子网掩码为 255.255.255.0那么192.168.0.X 在同一个网段,能互相访问. ...
- MySQL(4):数据表创建
数据库是表的容器,表,必须属于某个数据库. 可以通过.语法,指明数据表所属的数据库 比如:database.table 进行表操作的时候,都会指定当前的默认数据库. use db_name; 1.创建 ...
- rust haskell
http://www.rust-lang.org <null>
- ios定制中间突出的tabBar
我觉得有两个思路,一个是自己写tabBar 通过自定义实现,缺点呢就是比较麻烦,优点就是代码比较清楚,而且比较稳定. 另一个思路就是写个大按钮加在tabBar上 通过监听tabitem的点击来实现相 ...
- ios webview 图片自适应屏幕宽度
//这个知识点主要是自己最近在尝试写后台接口 在移动端展示的时候需要用到这个知识点,在webViewDidFinishLoad方法里面执行一段js代码 拿到各个图片 判断其宽度是否大于当前手机屏幕尺寸 ...
- Java栈实现
栈数组实现一:优点:入栈和出栈速度快,缺点:长度有限(有时候这也不能算是个缺点) public class Stack { private int top = -1; private Object[] ...
- 关于@see注解
所有三种类型的注释文档都可包含@see标记,它允许我们引用其他类里的文档.对于这个标记,javadoc会生成相应的HTML,将其直接链接到其他文档.格式如下: @see 类名@see 完整类名@see ...
- Javascript实现图片无缝滚动
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- HTTP 错误 500.21 - Internal Server Error的解决方案
开始菜单>所有程序>附件>命令提示符(以管理员的身份运行) 然后运行下面的命令注册: 32位机器: C:\Windows\Microsoft.NET\Framework\v4.0.3 ...
- TCP/IP 学习博客
原作者地址:http://blog.csdn.net/goodboy1881/article/category/204448