`

update 子查询

阅读更多
基础知识
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 子查询使用介绍

    主要介绍了update 子查询使用介绍,需要的朋友可以参考下

    MySQL锁类型以及子查询锁表问题、解锁1

    MySQL锁类型以及查询锁表问题、解锁MySQL中select * for update锁表的范围MySQL中select * for update锁表的问题由

    oracle中的子查询

    oracle中的子查询使用场合,种类,使用方法,错误排除

    Oracle的pl/sql和sqlplus

    1.练习利用SQL*Plus编写、执行PL/SQL程序的命令。 2.记录执行命令和操作过程中遇到的问题及解决方法,注意从原理上解释原因。 3.练习利用PLSQL Developer编写和管理存储过程、存储函数和触发器等。

    MySQL数据库update更新子查询

     UPDATE test.tb_vobile a  set a.name = '111 '  WHERE  a.id = (select max(id) id from test.tb_vobile)  报错:  [SQL]UPDATE test.tb_vobile a  set a.name = '111 '  WHERE  a.id = (select...

    利用带关联子查询Update语句更新数据的方法

    主要介绍了利用带关联子查询Update语句更新数据的方法,需要的朋友可以参考下

    数据库多表查询及嵌套查询子查询语句示例

    简单数据库但表查询 select * from kjbdsjk where 姓名 = 王勇 and 分数 = 87...7.在UPDATE语句中应用子查询:update kjbdsjk set 工资 = 工资+1000 where 工资 in (select 工资 from kjbdsjk where 工资 > "+stredit+")

    p/l sql查询

    常用的oracle查询 组合查询 子查询 P/L SQL 查询

    解决MySQL中IN子查询会导致无法使用索引问题

    主要介绍了MySQL中IN子查询会导致无法使用索引问题,文章给大家介绍了两种子查询的写法,需要的朋友可以参考下

    C#在Update语句中使用子查询

    摘要:C#源码,数据库应用,子查询 C#在Update语句中使用子查询,源代码免费下载。

    SQL子查询语句简单示例

     子查询能够与 SELECT、INSERT、UPDATE 和 DELETE 语句一起使用。  下面以 SELECT 语句作为示例: SELECT id, name FROM table1 WHERE id in ( SELECT id FROM table2);  在上面所给的例子中,我们将子...

    精通SQL 结构化查询语言详解

    10.2.2 IN子查询实现集合交和集合差运算 10.2.3 EXISTS子查询  10.2.4 EXISTS子查询实现两表交集  10.2.5 SOME/ALL子查询  10.2.6 UNIQUE子查询  10.3 相关子查询  10.3.1 使用IN引入相关子查询  ...

    SQL编程之子查询及注意事项

    子查询是一个 SELECT 语句,它嵌套在一个 SELECT、SELECT…INTO 语句、INSERT…INTO 语句、DELETE 语句、或 UPDATE 语句或嵌套在另一子查询中。 语法:select ….from 表1 where 列1 > (子查询) 外面的查询成为父...

    PostgreSQL 10 基础课程第五章 高级知识Update及Delete子查

    PostgreSQL 10 基础课程第五章 高级知识Update及Delete子查询

    MySQL的子查询中FROM和EXISTS子句的使用教程

    FROM 子查询 FROM 子句中的子查询 MySQL FROM 子查询是指 FROM 的子句作为子查询语句,主查询再到子查询结果中获取需要的数据。FROM 子查询语法如下: SELECT ... FROM (subquery) AS name ... 子查询会生成一个...

    MySql数据库中的子查询与高级应用浅析

    MySql数据库中的子查询: 子查询:在一条select查询语句中嵌套另一条select语句,其主要作用是充当查询条件或确定数据源。 代码案例如下: 例1. 查询大于平均年龄的学生: select * from students where age > ...

    SQL Server T-SQL高级查询

    子查询是一个嵌套在select、insert、update或delete语句或其他子查询中的查询。任何允许使用表达式的地方都可以使用子查询。子查询也称为内部查询或内部选择,而包含子查询的语句也成为外部查询或外部选择

    精通sql结构化查询语句

    11.1.4 由VALUES关键字插入多行数据 11.1.5 使用SELECT语句插入数据 11.1.6 通过视图插入数据 11.1.7 使用子查询插入数据 11.2 数据的更新操作 11.2.1 UPDATE语句的基本语法 11.2.2 使用UPDATE语句更新指定的列值 ...

    SQL查询技巧(范例宝典)

     实例348 在Update语句中应用子查询 511  10.14 联合语句Union 512  实例349 使用联合查询 512  实例350 多表联合查询 514  实例351 对联合查询后的结果进行排序 515  10.15 内联接查询 517 ...

    oracle 高级查询

    相关子查询在对每个候选行必须返回一个不同结果的子查询是有用的 EXISTS运算符是一个布尔林运算符,测试数值是否存在 相关于查询可以和SELECT,UPDATE和DELETE命令一起使用 当相同的查询发生多次,你可以使用WITH...

Global site tag (gtag.js) - Google Analytics