oracle 优化更新查询以根据其他表中的数据更新列中的所有空值

pftdvrlh  于 2023-11-17  发布在  Oracle
关注(0)|答案(3)|浏览(180)

我最近在ORACLE DB中创建了这个脚本来更新我刚刚创建的列上的所有现有值。然而,我被告知exists函数非常慢,我应该使用update使用join代替。不幸的是,我很难找到有用的例子和/或如何在ORACLE DB中正确执行的信息。

UPDATE appeal app
SET app.is_initial = (CASE WHEN EXISTS(SELECT 1
                                             FROM appeal app_sub
                                                      JOIN event_person ep ON app_sub.id = ep.appeal_id
                                                      JOIN event ON ep.event_id = event.id
                                             WHERE event.name_code = 'INITIAL' AND app.id = app_sub.id)
                                     THEN 1 ELSE 0 END)
WHERE app.is_initial IS NULL;

字符串
如果有人知道如何做到这一点,我将非常感谢的帮助。PS。我已经改变了安全表的名称。

vmjh9lq9

vmjh9lq91#

您可以使用left join尝试Merge

MERGE INTO  appeal TRG
 USING(
 SELECT appeal.id,CASE WHEN appeal_id IS NULL THEN 0 ELSE 1 END NEW_VAL
 FROM appeal app_sub
 LEFT JOIN event_person ep ON app_sub.id = ep.appeal_id
 INNER JOIN event ON ep.event_id = event.id
 WHERE name_code = 'INITIAL' 
 )SRC
 ON (TRG.ID=SRC.ID)
 WHEN MATCHED THEN UPDATE
 set TRG.is_initial=SRC.NEW_VAL
 where TRG.is_initial IS NULL;

字符串

7cjasjjr

7cjasjjr2#

EXISTS不一定很慢,但也有可能很慢。这里有几点需要检查:
你有app.idevent_person.appeal_idevent.id的索引吗?除非甲骨文重写这一点,标准的EXISTS子查询将使用嵌套循环,您需要对连接列进行正确的索引,以使其性能良好。只需确保这些索引到位,就可能解决您的问题,而无需重写SQL。如果您有一个小数据集,我建议你这么做。
但是,对于非常大的卷,使用MERGE通常可以获得更好的性能,这使您能够使用更有效的并行和直接路径扫描以及散列连接来组装数据以驱动更新。在大多数情况下,它通常不会使用索引。它看起来像这样(过度暗示只是为了说明这一点(并确保),这些提示中的大多数可能是不必要的)。

ALTER SESSION ENABLE PARALLEL DML;

MERGE /*+ USE_HASH(src app) parallel(app,8) */ INTO appeal app
USING (SELECT /*+ parallel(8) NO_MERGE USE_HASH(app_sub ep event) */
              app_sub.id,
              MAX(DECODE(event.id,NULL,0,1)) at_least_one
         FROM appeal app_sub
              LEFT OUTER JOIN event_person ep ON app_sub.id = ep.appeal_id
              LEFT OUTER JOIN event ON ep.event_id = event.id
        WHERE name_code = 'INITIAL'
          AND app_sub.is_initial IS NULL
        GROUP BY app_sub.id) src
   ON (src.id = app.id)
 WHEN MATCHED THEN UPDATE SET app.is_initial = src.at_least_one

字符串
(我不知道name_code来自哪个表;确保它没有被索引,或者如果是,确保Oracle没有使用该索引,并添加FULL([table])提示以防止它这样做。
最后,对于非常大的卷,最佳方法是根本不更新,而是创建一个新表并替换旧表:

CREATE TABLE appeal2 parallel (degree 8)
AS
SELECT /*+ USE_HASH(app epx) */
       app.id,
       app.col1,
       app.col2,
       app.col3,
       NVL(app.is_initial,DECODE(apx.appeal_id,NULL,0,1)) is_initial
  FROM appeal app
       LEFT OUTER JOIN (SELECT /*+ NO_MERGE USE_HASH(ep event) */
                               ep.appeal_id,
                          FROM event_person ep
                               INNER JOIN event ON ep.event_id = event.id
                         WHERE name_code = 'INITIAL'
                         GROUP BY ep.appeal_id) epx ON epx.appeal_id = app.appeal_id;

ALTER TABLE appeal RENAME TO appeal_old;
ALTER TABLE appeal2 RENAME TO appeal;

-- also rebuild and indexes, constraints and reissue grants.


创建新的段总是比更新表的每一行快得多,也更有效。如果表很小,不值得额外的步骤,但如果你谈论的是数亿或数十亿行,这是你最有效的方法。

o7jaxewo

o7jaxewo3#

假设name_codeeventevent_person表中,那么您似乎不需要在子查询中使用APPEAL,并且可以将其简化为:

UPDATE appeal app
SET app.is_initial = (SELECT LEAST(COUNT(*), 1)
                      FROM   event_person ep
                             INNER JOIN event
                             ON ep.event_id = event.id
                      WHERE  name_code = 'INITIAL'
                      AND    app.id = ep.appeal_id)
WHERE app.is_initial IS NULL;

字符串
或者:

UPDATE appeal app
SET app.is_initial = COALESCE(
                       ( SELECT 1
                         FROM   event_person ep
                                INNER JOIN event
                                ON ep.event_id = event.id
                         WHERE  name_code = 'INITIAL'
                         AND    app.id = ep.appeal_id
                         AND    ROWNUM = 1 ),
                       0
                     )
WHERE app.is_initial IS NULL;


fiddle

相关问题