基础知识
1, 关联子查询和非关联子查询
在非关联子查询中,内部查询只执行一次并返回它的值给外部查询,然后外部查询在它的处理中使用内部查询返回给它的值。而在关联子查询中,对于外部查询返回的每一行数据,内部查询都要执行一次。另外,在关联子查询中是信息流是双向的。外部查询的每行数据传递一个值给子查询,然后子查询为每一行数据执行一次并返回它的记录。然后,外部查询根据返回的记录做出决策。
如:
SELECT o1.CustomerID, o1.OrderID, o1.OrderDate
FROM Orders o1
WHERE o1.OrderDate = (SELECT Max(OrderDate)
FROM Orders o2
WHERE o2.CustomerID = o1.CustomerID)
是一个关联子查询
SELECT o1.CustomerID, o1.OrderID, o1.OrderDate
FROM Orders o1
WHERE o1.OrderDate IN
(SELECT TOP 2 o2.OrderDate
FROM Orders o2
WHERE o2.CustomerID = o1.CustomerID)
ORDER BY CustomerID
是一个非关联子查询
2, 提示(HINT)
一般在优化时,无论采用基于规则的或是基于代价的方法,由Oracle系统的优化器来决定语句的执行路径。这样的选择的路径不要见得是最好的。所以,Oracle提供了一种方法叫提示的方法。它可以让编程人员按照自己的要求来选择执行路径,即提示优化器该按照什么样的执行规则来执行当前的语句。这样可以在性能上比起Oracle优化自主决定要好些。
通常情况下,编程人员可以利用提示来进行优化决策。通过运用提示可以对下面内容进行指定:
l SQL语句的优化方法;
l 对于某条SQL语句,基于开销优化程序的目标;
l SQL语句访问的访问路径;
l 连接语句的连接次序;
l 连接语句中的连接操作。
如果希望优化器按照编程人员的要求执行,则要在语句中给出提示。提示的有效范围有限制,即有提示的语句块才能按照提示要求执行。下面语句可以指定提示:
l 简单的SELECT ,UPDATE ,DELETE 语句;
l 复合的主语句或子查询语句;
l 组成查询(UNION)的一部分。
提示的指定有原来的注释语句在加“+”构成。语法如下:
[ SELECT | DELETE|UPDATE ] /*+ [hint | text ] */
或
[ SELECT | DELETE|UPDATE ] --+ [hint | text ]
注意在“/*”后不要空就直接加“+”,同样 “--+”也是连着写。
警告:如果该提示语句书写不正确,则Oracle就忽略掉该语句。
常见的提示有:
Ordered 强制按照from子句中指定的表的顺序进行连接
Use_NL 强制指定两个表间的连接方式为嵌套循环(Nested Loops)
Use_Hash 强制指定两个表间的连接方式为哈希连接(Hash Join)
Use_Merge 强制指定两个表间的连接方式为合并排序连接(Merge Join)
Push_Subq 让非关联子查询提前执行
Index 强制使用某个索引
3, 执行计划
在PL/SQL Developer的SQL WINDOWS中用鼠标或键盘选中SQL语句,然后按F5,就会出现执行计划解析的界面:
4, Update的特点
Update的系统内部执行情况可以参照附文:对update事务的内部分析.doc
使用Update的基本要点就是,
1) 尽量使用更新表上的索引,减少不必要的更新
2) 更新的数据来源花费时间尽可能短,如果无法做到就把更新内容插入到中间表中,然后给中间表建上索引,再来更新
3) 如果更新的是主键,建议删除再插入。
5, 示例用表
后面的阐述将围绕以下两张表展开:
Create table tab1 (workdate varchar2(8), cino varchar2(15), val1 number, val2 number);
Create table tab2 (workdate varchar2(8), cino varchar2(15), val1 number, val2 number);
Create table tab3 (workdate varchar2(8), cino varchar2(15), val1 number, val2 number);
Create table tab4 (workdate varchar2(8), cino varchar2(15), val1 number, val2 number);workdate, cino为两张表的关键字,默认情况没有建主键索引。
二,Update两种情况
用Update更新某个表,无外乎是两种情况:根据关联子查询,更新字段;通过非关联子查询,限定更新范围。如果还有第三种情况,那就是前两种情况的叠加。
1, 根据关联子查询,更新字段
Update tab1 t
Set (val1, val2) = (select val1, val2
from tab2
where workdate = t.workdate
and cino = t.cino);
通过tab2来更新tab1的相应字段。执行SQL语句时,系统会从tab1中一行一行读记录,然后再通过关联子查询,找到相应的字段来更新。关联子查询能否通过tab1的条件快速的查找到对应记录,是优化能否实现的必要条件。所以一般都要求在tab2上建有Unique或者排重性较高的Normal索引。执行所用时间大概为(查询tab1中一条记录所用的时间 + 在tab2中查询一条记录所用的时间)* tab1中的记录条数。
如果子查询条件比较复杂,如以下语句:
Update tab1 t
Set (val1, val2) = (select val1, val2
from tab2 tt
where exists (select 1
from tab3
where workdate = tt.workdate
and cino = tt.cino)
and workdate = t.workdate
and cino = t.cino);这时更新tab1中的每条记录花费在子查询上的时间将成倍增加,如果tab1中的记录数较多,这种更新语句几乎是不可完成。
解决方式是,把子查询提取出来,做到中间表中,然后给中间表建上索引,用中间表来代替子查询,这样速度就能大大提高:
Insert into tab4
select workdate, cino, val1, val2
from tab2 tt
where exists (select 1
from tab3
where workdate = tt.workdate
and cino = tt.cino);
create index tab4_ind01 on tab4(workdate, cino);
Update tab1 t
Set (val1, val2) = (select val1, val2
from tab4 tt
where workdate = t.workdate
and cino = t.cino);
2, 通过非关联子查询,限定更新范围
Update tab1 t
set val1 = 1
where (workdate, cino) in (select workdate, cino from tab2)
根据tab2提供的数据范围,来更新tab1中的相应记录的val1字段。
在这种情况下,系统默认执行方式往往是先执行select workdate, cino from tab2子查询,在系统中形成系统视图,然后在tab1中选取一条记录,查询系统视图中是否存在相应的workdate, cino组合,如果存在,则更新tab1,如果不存在,则选取下一条记录。这种方式的查询时间大致等于:子查询查询时间 + (在tab1中选取一条记录的时间 + 在系统视图中全表扫描寻找一条记录时间)* tab1的记录条数。其中“在系统视图中全表扫描寻找一条记录时间”会根据tab2的大小而有所不同。若tab2记录数较小,系统可以直接把表读到系统区中;若tab2记录数多,系统无法形成系统视图,这时会每一次更新动作,就把子查询做一次,速度会非常的慢。
针对这种情况的优化有两种
1) 在tab1上的workdate, cino字段上加入索引,同时增加提示。
修改以后的SQL语句如下:
Update /*+ordered use_nl(sys, t)*/ tab1 t
set val1 = 1
where (workdate, cino) in (select workdate, cino from tab2)
其中sys表示系统视图。如果不加入ordered提示,系统将会默认以tab1表作为驱动表,这时就要对tab1作全表扫描。加入提示后,使用系统视图,即select workdate, cino from tab2,作为驱动表,在正常情况下,速度能提高很多。
2) 在tab2表上的workdate, cino字段加入索引,同时改写SQL语句:
Update tab1 t
set val1 = 1
where exists (select 1
from tab2
where workdate = t.workdate
and cino = t.cino)
三,索引问题
update索引的使用比较特殊,有时看起来能用全索引,但实际上却只用到一部分,所以建议把复合索引的各字段写在一起。
例如:
Update /*+ordered use_nl(sys, t)*/ tab1 t
set val1 = 1
where cino in (select cino from tab2)
and workdate = '200506'
这条SQL语句是不能完全用到tab1上的复合索引workdate + cino的。能用到的只是workdate=’200506’的约束。
如果写成这样,就没问题:
Update /*+ordered use_nl(sys, t)*/ tab1 t
set val1 = 1
where (workdate, cino) in (select workdate, cino from tab2)
分享到:
相关推荐
本文将深入探讨`UPDATE`子查询的使用、关联子查询与非关联子查询的区别、提示(HINT)的使用以及执行计划的查看,并提供实际示例。 1. **关联子查询与非关联子查询** - **关联子查询**:在关联子查询中,外部查询...
在实际应用中,可能会遇到死锁问题,特别是在涉及子查询的更新语句中。如描述中所示,如果一个事务在更新时对子查询中的表进行锁定,可能导致其他事务尝试获取已被锁定的资源,从而引发死锁。MySQL在检测到死锁时会...
### Oracle中的子查询详解 #### 一、子查询概述与应用场景 子查询是SQL语言中一项非常重要的功能,它允许我们在一个查询语句中嵌入另一个查询语句,以此来解决复杂的查询问题。子查询可以极大地提高SQL语言的灵活...
本篇将深入探讨如何在`UPDATE`语句中正确使用子查询,并提供相关的解决方案。 首先,我们要明白在`UPDATE`语句中直接使用子查询可能引发的问题。例如,当我们尝试像这样更新数据: ```sql UPDATE test.tb_vobile a...
【Update语句更新与关联子查询】在数据库操作中,Update语句用于更新表中的已有数据,而关联子查询则是将一个查询嵌套在另一个查询的WHERE子句中,以根据某个条件从关联的表中获取数据。在某些复杂的场景下,我们...
它结合了SQL的查询功能和过程性编程语言的控制结构,使得数据库管理和应用开发更为灵活高效。SQL*Plus是Oracle提供的一种命令行工具,可以用来编写和执行SQL及PL/SQL语句。 在PL/SQL中,语句块是基本的执行单元,...
子查询总是写在圆括号中,可以用在使用表达式的任何地方,如 Select、Insert、Update 或 Delete 语句或其他子查询中。 子查询也称为内部查询或内部选择,而包含子查询的语句也称为外部查询或外部选择。许多包含子...
子查询总是被写在圆括号中,并且可以被用在使用表达式的任何地方,例如:嵌套在 `SELECT`、`INSERT`、`UPDATE` 或 `DELETE` 语句中,甚至其他子查询中。 #### 二、子查询的特点与用途 子查询也被称为**内部查询**或...
SQL子查询和嵌套查询是数据库管理中非常重要的概念,主要用于处理复杂的数据检索任务。它们允许在单一的查询语句中嵌入其他查询,以实现更复杂的逻辑和数据筛选。 首先,让我们详细了解什么是嵌套查询。嵌套查询,...
### 在ADO(SQL)中使用SELECT的语法之六——子查询的使用方法 #### 一、子查询概述 在SQL查询语言中,子查询是一个非常重要的概念。子查询是指在一个SQL命令内部嵌套另一个完整的SQL查询命令。通过使用子查询,我们...
子查询可以被用在SELECT、INSERT、UPDATE和DELETE命令中,甚至可以在一个子查询内部再嵌套其他子查询,以实现复杂的数据操作和分析。下面将详细讲解Oracle子查询的使用及其在上述示例中的应用。 1. **子查询的类型...
第五,用MERGE改写UPDATE子查询。MERGE命令是Oracle9i及以后版本新增的命令,其字面上的意思就是合并、兼并,用来合并UPDATE和INSERT语法。通过 MERGE 命令,根据一张表或子查询的连接条件对数据进行合并、更新和...
子查询可以是单行子查询(返回一行一列)、多行子查询(返回多行一列)或者集合子查询(返回多行多列)。子查询的灵活性使其在复杂查询中扮演了重要角色。 然后是**PL/SQL**,它是Oracle数据库提供的过程化语言,...
子查询可以出现在SELECT、UPDATE或DELETE语句中,通常作为WHERE或HAVING子句的一部分。在本章的学习中,我们将深入探讨子查询的使用,包括不同类型的子查询、在WHERE和HAVING子句中的应用,以及如何使用IN、ANY、ALL...
子查询总是写在圆括号中,可以用在使用表达式的任何地方,如Select、Insert、Update或Delete语句或其他子查询中。子查询也称为内部查询或内部选择,而包含子查询的语句也称为外部查询或外部选择。 子查询的组件包括...
子查询可以被用作SELECT、INSERT、UPDATE或DELETE语句的一部分,它可以返回单个值、多行单列的结果集或者多行多列的结果集。在易语言中,子查询的应用主要体现在以下几个方面: 1. **单行子查询**:这种子查询返回...
子查询可以在SELECT、INSERT、UPDATE或DELETE命令中作为表达式的一部分出现,甚至可以嵌套在其他子查询中。其基本语法结构包括在一个SELECT语句中定义子查询,通常用圆括号括起来。子查询不能包含COMPUTE或FOR ...