【问题标题】:oracle update with correlated query具有相关查询的 oracle 更新
【发布时间】:2020-02-16 20:09:27
【问题描述】:

正确答案是什么?选择两个。

检查此 SQL 语句:

UPDATE orders o
SET customer_name = (
    SELECT cust_last_name FROM customers  WHERE customer_id=o.customer_id
);

哪两个是真的?

  • A.子查询在执行 UPDATE 语句之前执行。

  • B. ORDERS 表中的所有现有行都会更新。

  • C.对 ORDERS 中每个更新的行执行子查询 表。

  • D. UPDATE 语句执行成功,即使子查询 选择多行。

  • E.子查询不是相关子查询。

我知道 B 是正确的,但我认为所有其他选择都不正确。

  • A.子查询为外部查询返回的每一行执行,所以 它应该在外部查询之后执行。

  • C.不是针对每个更新的行,而是针对外部的每一行 查询返回。

  • D.我试过。它导致错误 ORA-01427: 单行子查询返回 不止一行

  • E.它是一个相关子查询。

【问题讨论】:

    标签: sql oracle sql-update correlated-subquery


    【解决方案1】:

    考虑选项 C:

    C.对 ORDERS 表中每个更新的行执行子查询。

    你说:

    不是针对每个更新的行,而是针对外部查询返回的每一行。

    是的。子查询确实针对外部查询中的每一行执行(不考虑数据库应用的可能优化)。并且外部查询中的每一行都会更新 - 正如您所发现的,因为您已经并且正确地选择了选项 B:ORDERS 表中的所有现有行都已更新

    注意:您反对选项 A、D 和 3 的论点是有效的。

    【讨论】:

    • 这个答案(对于 Oracle)在 20 年前是正确的,但在最近的版本中绝对不正确!
    • @MarmiteBomber:是的。我在回答中提到了可能的优化。但我怀疑这是原始问题的提问者(可能是老师)所期望的专业水平。因此我的回答。
    • 好吧,缺乏提问者的专业知识我完全同意你的看法。他/她在对订单表中的客户名称进行非规范化时从未听说过normal form;)
    【解决方案2】:

    唯一的第二个正确答案是

    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 次,即几乎每个客户仅访问一次并且每个订单不访问一次

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-29
      相关资源
      最近更新 更多