0

可以重写以下查询吗?它需要花费大量时间来执行,并且有大量数据会引发临时空间问题。我认为 Merge 会提高性能。请建议并帮助我以更好的方式重写它

Update table1 
Set Tgt_col ='2'
where col1 in (
SELECT  ls.col1
 FROM table1 ls 
WHERE ls. Col2 ||ls. col3||ls.col22||To_Char(ls.time_col,'YYYYMMDD') IN (
  SELECT  o1. Col2||o1. col3||o1. col22||To_Char(o1. time_col,'YYYYMMDD')
  FROM table1 o1
  INNER JOIN table1 o2 ON o1. Col2 = o2. Col2
  WHERE o1. col3<> o2. col3
  AND  Nvl(o1. col22, 'XX') = Nvl(o2. col22, 'XX')
  AND To_Char(o1. time_col,'YYYYMMDD') = To_Char(o2. time_col,'YYYYMMDD')
  AND o1.date_col = :A
  AND o2. date_col = :A
  AND o1.col10 = o2.col10
  AND o1.col4 IN ('A','B','C')
  AND o1.is_root=0 AND o1.is_leaf=1
  AND o2. col4 IN ('A','B','C')
  AND o2.is_root=0 AND o2.is_leaf=1
  AND o1.col5 IN ('US','CA')
  AND o2.col5 IN ('US','CA')
GROUP BY o1. Col2||o1. col3||o1. col22||To_Char(o1. time_col,'YYYYMMDD')
)
AND ls. col4 IN ('A','B','C')
AND ls.tgt_col IS NULL
AND ls. date_col = :A
AND ls.col5 IN ('US','CA')
AND ls.ID1 IN (SELECT ID1 FROM table2 F
                                          WHERE F.col6 IN (SELECT col6  FROM table3
                                                               WHERE date_col =:A AND col7 = 1 )
                                                                                                                AND F.col8 = '1')
);
4

2 回答 2

0

在没有要测试的数据的情况下,我认为以下内容会比您当前的查询更快:

UPDATE table1
SET    tgt_cl = '2'
WHERE  col1 IN (SELECT col1
                FROM   (SELECT o1.col1,
                               o1.col2,
                               o1.col3,
                               o1.col22,
                               o1.time_col,
                               COUNT(DISTINCT o1.col3) OVER (PARTITION BY o1.col2, o1.col3, o1.time_col, o1.col10, o1.col22) dcnt
                        FROM   table1 o1
                        WHERE  o1.date_col = :a
                        AND    o1.col4 IN ('A', 'B', 'C')
                        AND    o1.is_root = 0
                        AND    o1.is_leaf = 1
                        AND    o1.col5 IN ('US', 'CA')
                        AND    o1.col3 IS NOT NULL)
                WHERE  dcnt > 1
                AND    id1 IN (SELECT id1
                               FROM   table2 f
                               WHERE  f.col6 IN (SELECT col6
                                                 FROM   table3
                                                 WHERE  date_col = :a
                                                 AND    col17 = 1)
                               AND    f.col8 = '1'));

看起来您正在尝试在 table1 中查找 col1 值,这些值对于每个 col2、col3、time_col、col10 和 col22 组合具有多个不同的 col3 值,因此我使用了分析计数函数来找出它。您可能会发现 EXISTS 比 IN 更好;由您来测试 a)我的查询是否有效,以及 b)用 EXISTS 替换 IN 是否对您的数据更快。

于 2019-02-07T15:38:23.190 回答
0

试试下面的代码,应该会更快:

UPDATE table1
   SET Tgt_col = '2'
 WHERE EXISTS (SELECT 1
                 FROM table1 ls
                 JOIN table2 F
                   ON (f.ID1 = ls.ID1)
                 JOIN table3 t3
                   ON (t3.col6 = F.col6
                       -- IF :A is always inserted, you can remove if-null checkings for this date_col
                       AND (   (t3.date_col is null AND ls.date_col is null)
                            OR t3.date_col = ls.date_col
                            )
                       )
                WHERE ls.col1 = table1.col1
                  AND EXISTS (SELECT 1
                                FROM table1 o1
                                JOIN table1 o2 
                                  ON (o1.Col2 = o2.Col2
                                      AND o1.col10 = o2.col10
                                      AND o1.is_root = o2.is_root
                                      AND o1.is_leaf = o2.is_leaf
                                      AND (   (o1.time_col is null AND o2.time_col is null)
                                           OR o1.time_col = o2.time_col
                                           )
                                      AND (   (o1.col22 is null AND o2.col22 is null)
                                           OR o1.col22 = o2.col22
                                           )
                                      -- IF :A is always inserted, you can remove if-null checkings for date_col
                                      AND (   (o1.date_col is null AND o2.date_col is null)
                                           OR o1.date_col = o2.date_col
                                           )
                                      AND o1.col3 != o2.col3)
                               WHERE     (o1.Col2 = ls.Col2 OR (o1.Col2 is null AND ls.Col2 is null))
                                     AND (o1.col3 = ls.col3 OR (o1.col3 is null AND ls.col3 is null))
                                     AND (o1.col22 = ls.col22 OR (o1.col22 is null AND ls.col22 is null))
                                     AND (o1.time_col = ls.time_col OR (o1.time_col is null AND ls.time_col is null))
                                     -- IF :A is always inserted, you can remove if-null checkings for this date_col
                                     AND (o1.date_col = ls.date_col OR (o1.date_col is null AND ls.date_col is null))
                                     AND o1.is_root = 0
                                     AND o1.is_leaf = 1
                                     -- IF o1.col4 should be equal to o2.col4 THEN also add it inside `ON` and remove one of two from here
                                     AND o1.col4 IN ('A', 'B', 'C')
                                     AND o2.col4 IN ('A', 'B', 'C')
                                     -- IF o1.col5 should be equal to o2.col5 THEN also add it inside `ON` and remove one of two from here
                                     AND o1.col5 IN ('US', 'CA')
                                     AND o2.col5 IN ('US', 'CA')
                                     AND rownum = 1)
                  -- IF ls.col4 should be equal to col4 from inside the subquery THEN add it inside as, for example, for col22
                  AND ls.col4 IN ('A', 'B', 'C')
                  AND ls.tgt_col IS NULL
                  AND ls.date_col = :A
                  -- IF ls.col5 should be equal to col5 from inside the subquery THEN add it inside as, for example, for col22
                  AND ls.col5 IN ('US', 'CA')
                  AND F.col8 = '1'
                  AND t3.col7 = 1
                  AND rownum = 1);

主要区别在于:

  • 删除连接并用 where 子句中的比较值对其进行补充
  • 使用EXISTSwithrownum代替IN
  • 使用 ofJOIN代替INfortable2 Ftable3比较

如果col1是唯一键,则将所有ls table检查写入外部查询 ( ) 以减少通过检查ls.col4 IN ('A', 'B', 'C') AND ls.tgt_col IS NULL AND ls.date_col = :A AND ls.col5 IN ('US', 'CA')的行数。EXISTS

代码内部的注释中也有更多提示。

始终在提交之前检查对数据的更改

我希望我有所帮助!

于 2019-02-07T15:16:28.163 回答