0

我有一个表,其中存在 1220200 条重复记录。

我正在使用以下查询来删除重复记录。

DELETE /*+ NO_CPU_COSTING  */
  FROM  FCST f1
  WHERE
       ROWID >
           (SELECT MIN (ROWID)
              FROM FCST f2
             WHERE 
                  f1.DMDUNIT = f2.DMDUNIT
                   AND f1.DMDGROUP = f2.DMDGROUP
                   AND f1.LOC = f2.LOC
                   AND f1.STARTDATE = f2.STARTDATE
                   AND f1.TYPE = f2.TYPE
                   AND UPPER (f1.FCSTID) = UPPER (f2.FCSTID));

删除这些记录大约需要 2 分钟。我也尝试了批量删除方法,方法是将重复数据加载到游标中并批量删除,但这需要更多时间。

优化此代码的更好方法是什么?

4

2 回答 2

1

一个简单的事情是这样的

delete /*+RULE*/ from t
where rowid in ( select rid
                   from ( select rowid rid,
                                 row_number() over
                                   (partition by cust_seg_nbr order by rowid) rn
                            from t
                        )
                 where rn <> 1 );

但是,如果您有大量数据,那么

检查此链接http://www.rampant-books.com/t_stoever_delete_duplicates.htm或使用下面的代码

 DECLARE     -- Code ©2004 by Edward Stoever
   CURSOR c_get_duplicates
   IS
      SELECT   ssrfees_term_code, ssrfees_crn, ssrfees_detl_code,
               ssrfees_ftyp_code, ssrfees_levl_code, COUNT (*)
          FROM ssrfees
        HAVING COUNT (*) > 1
      GROUP BY ssrfees_term_code,
               ssrfees_crn,
               ssrfees_detl_code,
               ssrfees_ftyp_code,
               ssrfees_levl_code;

   var_get_duplicates c_get_duplicates%ROWTYPE;

   CURSOR c_del_only_one
   IS
      SELECT ROWID
        FROM ssrfees
       WHERE ssrfees_term_code = var_get_duplicates.ssrfees_term_code
         AND ssrfees_crn = var_get_duplicates.ssrfees_crn
         AND ssrfees_detl_code = var_get_duplicates.ssrfees_detl_code
         AND NVL(ssrfees_ftyp_code,'1') = NVL(var_get_duplicates.ssrfees_ftyp_code,'1')
         AND NVL(ssrfees_levl_code,'1') = NVL(var_get_duplicates.ssrfees_levl_code,'1');

   var_del_only_one ROWID;
BEGIN
   OPEN c_get_duplicates;

   LOOP
      FETCH c_get_duplicates
       INTO var_get_duplicates;

      EXIT WHEN c_get_duplicates%NOTFOUND;

      OPEN c_del_only_one;

      FETCH c_del_only_one
       INTO var_del_only_one;

      DELETE FROM ssrfees
            WHERE ROWID = var_del_only_one;

      COMMIT;

      CLOSE c_del_only_one;
   END LOOP;

   CLOSE c_get_duplicates;
END;
/
于 2013-06-17T09:24:49.017 回答
0

包含“ROWID > ...”的查询基本上是可疑的。

我认为您正在寻找的是:

DELETE FROM
  FCST f1
WHERE
  ROWID NOT IN (
    SELECT   MIN(ROWID)
    FROM     FCST f2
    GROUP BY f2.DMDUNIT,
             f2.DMDGROUP,
             f2.LOC,
             f2.STARTDATE,
             f2.TYPE,
             UPPER(f2.FCSTID));

子查询标识一组 ROWID,涵盖 GROUP BY 子句中列的所有唯一值,并删除所有其他列。

一个更快的替代方法可能是创建一个只包含要保留的行的新表,但如果这足够高性能,那么就坚持下去。

于 2013-06-17T10:02:07.490 回答