带有子查询的 Oracle 更新 - 性能问题

Posted

技术标签:

【中文标题】带有子查询的 Oracle 更新 - 性能问题【英文标题】:Oracle update with subquery - performanceissue 【发布时间】:2013-10-31 09:27:24 【问题描述】:

我的 oracle 数据库中的更新语句出现问题。 查询需要很长时间,并且临时表空间空间不足,但它提供了正确的数据。

我试图将子查询转换为联接,但我不知道如何正确地做到这一点。 如果有人知道如何改进语句或如何将其转换为联接,我将不胜感激。

        UPDATE table1 t1
        SET t1.inxdc = (SELECT sda_x
           FROM table2 t2
           WHERE t1.c1 = t2.c1
             AND t1.c2 = t2.c2
             AND t1.c3 = t2.c3
             AND t1.c4 = t2.c4
             AND t1.c5 = t2.c5
             AND t1.c6 = t2.c6
             AND t2.ident = 'K_SDA_W'
             AND rownum=1)
      WHERE EXISTS
          (SELECT 1
           FROM table2 t2
           WHERE t1.c1 = t2.c1
             AND t1.c2 = t2.c2
             AND t1.c3 = t2.c3
             AND t1.c4 = t2.c4
             AND t1.c5 = t2.c5
             AND t1.c6 = t2.c6
             AND t2.ident = 'K_SDA_W');

编辑1: 表格的一些信息

table1 PK = c1,c2,c3,c4,c5,c6 table2 PKs = ident,c4,c5,c6,以及声明中未提及的其他 3 个 (c7,c8,c9) 索引:除了 PK 仅在 table2 c1 上 table1 数据:12466 行 table2 数据:194827 行

编辑2: 执行计划

    --------------------------------------------------------------
    | Id  | Operation                     | Name                 |
    --------------------------------------------------------------
    |   0 | UPDATE STATEMENT              |                      |
    |   1 |  UPDATE                       | table1               |
    |   2 |   NESTED LOOPS SEMI           |                      |
    |   3 |    TABLE ACCESS FULL          | table1               |
    |   4 |    TABLE ACCESS BY INDEX ROWID| table2               |
    |   5 |     INDEX RANGE SCAN          | t2.c1                |
    |   6 |   COUNT STOPKEY               |                      |
    |   7 |    TABLE ACCESS BY INDEX ROWID| table2               |
    |   8 |     INDEX RANGE SCAN          | t2.PK                |
    --------------------------------------------------------------

【问题讨论】:

T1 和 T2 哪个更大? T1和T2的PK是多少?有索引吗? 您的表有多大,运行此更新需要多长时间?你能告诉我们执行计划吗?子查询是否使用一些索引?从table1 中的一个相关行的子查询中检索一个值需要多长时间? 为什么 rownum = 1? T2中是否有重复项?这是否意味着 T2 > T1 的大小?计划在说什么! 【参考方案1】:

Table1 中的行数很少,在这种特殊情况下只需删除WHERE 子句,并将NVL 添加到从子查询返回的值:

UPDATE table1 t1
        SET t1.inxdc = NVL((SELECT sda_x
           FROM table2 t2
           WHERE t1.c1 = t2.c1
             AND t1.c2 = t2.c2
             AND t1.c3 = t2.c3
             AND t1.c4 = t2.c4
             AND t1.c5 = t2.c5
             AND t1.c6 = t2.c6
             AND t2.ident = 'K_SDA_W'
             AND rownum=1), t1.inxdc);

一般来说你的更新应该很快,你检查过子查询的性能吗?检查table2 上是否为子查询使用了索引(以及哪个索引)(最好向我们展示执行计划)。

【讨论】:

【参考方案2】:

我认为表 t2 应该在 c1,c2,c3, c4,c5,c6,ident 上有一个索引 在这种情况下,t1 的更新应该会更快。

【讨论】:

以上是关于带有子查询的 Oracle 更新 - 性能问题的主要内容,如果未能解决你的问题,请参考以下文章

Oracle 在 IN 子句中使用子查询降低性能

使用子查询更新与使用连接更新 - 性能更好

带有相关子查询的 While 循环的 SQL Server 性能调整

带有在子查询中生成的值的 Oracle SQL 更新语句

SparkSQL 子查询和性能

带有子查询的 SQL 更新