唯一的第二个正确答案是
F。这是对orders 表中的CUSTOMER_NAME 进行非规范化的错误设计,因此与正常形式相冲突。
答案 C 在 Oracle 8 时代(即 20 年前)可能是正确的,但现在它肯定是错误的!。
Oracle 引入scalar subquery caching 事件的原因是限制子查询的执行次数。
这里是一个简单的演示
Oracle 19.2 中的这种设置有 10K 订单和 1K 客户。
create table customers as
select rownum customer_id, 'cust_'||rownum customer_name from dual connect by level <= 1000;
create index customers_idx1 on customers (customer_id);
create table orders as
select rownum order_id, trunc(rownum/10)+1 customer_id, cast (null as varchar2(100)) customer_name
from dual connect by level <= 10000;
按预期对 100K 行执行更新
UPDATE /*+ gather_plan_statistics */ orders o
SET customer_name = (
SELECT customer_name FROM customers WHERE customer_id=o.customer_id
);
提示gather_plan_statistics 收集我们将检查的执行统计信息。
SQL_ID 8r610vz9fknr6, child number 0
-------------------------------------
UPDATE /*+ gather_plan_statistics */ orders o SET customer_name = (
SELECT customer_name FROM customers WHERE customer_id=o.customer_id )
Plan hash value: 3416863305
--------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
--------------------------------------------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | | 0 |00:00:00.18 | 60863 | 21 |
| 1 | UPDATE | ORDERS | 1 | | 0 |00:00:00.18 | 60863 | 21 |
| 2 | TABLE ACCESS FULL | ORDERS | 1 | 10000 | 10000 |00:00:00.01 | 21 | 18 |
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED| CUSTOMERS | 1001 | 1 | 1000 |00:00:00.01 | 2020 | 3 |
|* 4 | INDEX RANGE SCAN | CUSTOMERS_IDX1 | 1001 | 1 | 1000 |00:00:00.01 | 1020 | 3 |
--------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("CUSTOMER_ID"=:B1)
重要信息在Start 列中,我们看到表customers 仅被访问了1001 次,即几乎每个客户仅访问一次并且每个订单不访问一次。