update 强制 NEST_LOOP NL 的理解,被驱动表 inner table

PURPOSE

This document suggests methods of processing update statements that contain subqueries so that the query drives off the subquery (i.e. it examines the subquery first before it looks at the table to be updated). This can have advantages when the subquery contains information that would allow indexes to be used on the updated table that would otherwise be unavailable. Note that the use of the techniques illustrated here are not restricted to updates but can be modified to affect many other queries.

DETAILS

Update with subquery not using index on updated table

Consider the following update:

UPDATE emp e

SET e.empno = e.empno

WHERE e.deptno in (SELECT d.deptno FROM dept d)

/

If there is an index on e.deptno then it is possible that this may be a good access path for emp. An index lookup can only be used if there is a value provided to lookup with (unless the whole index is scanned which is typically not cost effective). In this case a lookup can only be achieved if rows have already been retrieved from dept to drive the index lookup on emp. So to perform the index lookup on emp the query needs to access dept before it accesses emp. However it is likely that the plan chosen by default for this query will look something like:

Execution Plan

0 UPDATE STATEMENT Optimizer=CHOOSE (Cost=6 Card=1 Bytes=52)

1 0 HASH JOIN (Cost=6 Card=1 Bytes=52)

2 1 TABLE ACCESS (FULL) OF 'EMP' (Cost=1 Card=14 Bytes=546)

3 1 VIEW (Cost=4 Card=21 Bytes=273)

4 3 SORT (UNIQUE)

5 4 TABLE ACCESS (FULL) OF 'DEPT' (Cost=1 Card=21 Bytes=273)

In other words it looks at emp first as opposed to dept and so does not use the index since the indexed column does not have a value to lookup with.

The optimizer does consider driving the table from both emp & dept but since it does the evaluation on a cost basis it may choose to do the query in the order that you do not want. So how can the optimizer be forced to use the subquery to drive the update?

With a select, an ordered hint could be used together with modifications to the from clause to achieve the required join order. However, an update does not have a from clause so an ordered hint cannot be used in the same way.

How to get it to use an index:

The query can be forced in to a Nested Loop join with an ORDERED and a USE_NL hint:

SQL> UPDATE /*+ ORDERED USE_NL(E) INDEX(E) */ emp e

SET e.empno = e.empno

WHERE e.deptno in (SELECT d.deptno FROM dept d)

/

15 rows updated.

Execution Plan

0 UPDATE STATEMENT Optimizer=CHOOSE (Cost=46 Card=1 Bytes=52)

1 0 NESTED LOOPS (Cost=46 Card=1 Bytes=52)

2 1 VIEW (Cost=4 Card=21 Bytes=273)

3 2 SORT (UNIQUE)

4 3 TABLE ACCESS (FULL) OF 'DEPT' (Cost=1 Card=21 Bytes=273)

5 1 INDEX (RANGE SCAN) OF 'E_DNO' (NON-UNIQUE)

Notice that the USE_NL hint specifies the inner table E (emp). Since the hint has indicated that emp should be the inner table, this leaves Dept as the outer table. Since dept is the outer table it is accessed first (before emp) and so values retrieved from dept can be used to lookup in the E_DNO index.

USE_NL 两个一起也是可以的。

Alternative solutions

  • Use PLSQL. Use the select from dept as the driving cursor for the update. 这种肯定量大就不是高效的。
  • It may also be possible to create a view on both tables and update the view. However there are numerous restrictions with using this method. 直接update 两张表
  • merge 考虑一下
相关推荐
TDengine (老段)31 分钟前
TDengine 时间函数 WEEKDAY() 用户手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
TDengine (老段)39 分钟前
从 ETL 到 Agentic AI:工业数据管理变革与 TDengine IDMP 的治理之道
数据库·数据仓库·人工智能·物联网·时序数据库·etl·tdengine
LQ深蹲不写BUG3 小时前
MySql的事务机制
数据库·mysql
逼子格3 小时前
【Proteus仿真】定时器控制系列仿真——秒表计数/数码管显示时间
数据库·单片机·嵌入式硬件·51单片机·proteus·定时器·硬件工程师
stein_java4 小时前
Mybatis-7 XML映射器
数据库·sql·mybatis
xhbh6665 小时前
开发效率翻倍:资深DBA都在用的MySQL客户端利器
数据库·mysql·数据库连接工具·mysql 连接工具
LJC_Superman5 小时前
Web与Nginx网站服务
运维·服务器·前端·网络·数据库·nginx·vim
java水泥工5 小时前
校园管理系统|基于SpringBoot和Vue的校园管理系统(源码+数据库+文档)
数据库·vue.js·spring boot
高山有多高6 小时前
详解文件操作
c语言·开发语言·数据库·c++·算法