如何优化查询以使用oracle中另一个表中的列更新表列

Posted

技术标签:

【中文标题】如何优化查询以使用oracle中另一个表中的列更新表列【英文标题】:How to optimize the query to update a table column with a column in another table in oracle 【发布时间】:2020-02-19 13:00:15 【问题描述】:

我有 2 张桌子。一个表是 cr_archive,它有大约 9000000 条记录。它有一个名为 v_sales_person 的列,它没有值。我有另一个名为 table_2 的表,它具有名为 v_sales_person 的相同列,其中有值。两个表都有名为 product_label、account_num 的列。我想从表 _2 中选择与 cr_archive 具有相同 product_labels 和 account_num 的数据,并使用 table_2 中满足上述条件的值更新 cr_archive 中的 v_sales_person 列(使用 oracle)。我尝试了以下查询。

update cr_archive a
set a.v_sales_person = (select distinct b.v_sales_person from table_2 b where a.account_num = b.account_num and A.PRODUCT_LABEL=b.PRODUCT_LABEL )
/
commit
/

但是查询需要超过 6 个小时来处理并且不知道它是否给出了输出。我有 2 个问题。 1.上述查询是否正确? 2. 有什么方法可以优化上面的查询。

【问题讨论】:

你能发布一个执行计划和DDL吗?如果您要更新 9.000.000 行,则索引很重要。此外,“distinct”可能不是您想要的。 【参考方案1】:

不要在子查询中使用select distinct。它表明它可以返回不止一行。相反,请使用rownum = 1。所以,开始吧:

update cr_archive a
    set a.v_sales_person = (select b.v_sales_person
                            from table_2 b
                            where a.account_num = b.account_num and
                                  A.PRODUCT_LABEL = b.PRODUCT_LABEL and
                                  rownum = 1
                           );

您想使用table_2(account_num, PRODUCT_LABEL, v_sales_person) 上的索引来优化它。该索引对性能很重要。

接下来,这是更新所有行。如果这不是必需的,那么它是昂贵的。所以:

update cr_archive a
    set a.v_sales_person = (select b.v_sales_person
                            from table_2 b
                            where a.account_num = b.account_num and
                                  A.PRODUCT_LABEL = b.PRODUCT_LABEL and
                                  rownum = 1
                           )
    where a.v_sales_person is null or
          a.v_sales_person <> (select b.v_sales_person
                               from table_2 b
                               where a.account_num = b.account_num and
                                     A.PRODUCT_LABEL = b.PRODUCT_LABEL and
                                     rownum = 1
                              );

最后,如果您确实需要更新所有行,那么这将是相当昂贵的。您可能会发现以下一种可行的替代方案:

    重建表。大量插入比大量更新更快。 算了。当您查询表以获取名称时,只需 JOIN。 添加具有相同主键的新表。

【讨论】:

【参考方案2】:

您可以使用MERGE声明如下:

MERGE INTO CR_ARCHIVE A 
USING (
          SELECT
              MAX(B.V_SALES_PERSON) AS V_SALES_PERSON,
              B.ACCOUNT_NUM,
              B.PRODUCT_LABEL
          FROM
              TABLE_2 B
          GROUP BY
              B.ACCOUNT_NUM,
              B.PRODUCT_LABEL
      )
B ON ( A.ACCOUNT_NUM = B.ACCOUNT_NUM
       AND A.PRODUCT_LABEL = B.PRODUCT_LABEL )
WHEN MATCHED THEN 
UPDATE SET A.V_SALES_PERSON = B.V_SALES_PERSON;
/

干杯!!

【讨论】:

以上是关于如何优化查询以使用oracle中另一个表中的列更新表列的主要内容,如果未能解决你的问题,请参考以下文章

SQL 更新一个表中的值以匹配 Oracle SQL Developer 中另一个表的值

如何使用laravel中另一个表中的外键获取所需的列

如何使用计数查询来(自动)更新表中的列

如何在子查询中使用外部查询中的列从另一个表中获取结果?

如何使用同一表中的列进行更新(ORACLE)

使用 ClickHouse 中另一个表中的值更新行