2012-07-25 173 views
0

我有一個表,其中存在1220200個重複記錄。Oracle:批量刪除重複記錄

我正在使用下面的查詢來刪除重複的記錄。

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分鐘去除120萬個副本似乎是相當合理的。 – 2012-07-25 13:33:18

+0

嗨託尼,感謝您的快速響應。這是遷移的一部分,它將在每次從樣本轉儲設置新數據庫時執行。 – Anand 2012-07-25 15:42:45

+0

除了解決方案,我更有興趣瞭解是否可以使用類型,批量收集或可能並行pl/sql優化它? – Anand 2012-07-25 16:00:32

回答

0

一件簡單的事情做的就是這樣的事情

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; 
/
+0

如果你有大量的數據,那麼我會懷疑你想要的最後一種方法是使用嵌套遊標,特別是當包含提交時。這看起來像一個糟糕的表現配方。 – 2013-06-17 10:03:38

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的,涵蓋所有在該組的列BY子句中的唯一值,且其他所有刪除。

更快的替代方案可能是創建一個只包含要保留的行的新表,但如果這足夠高性能,請堅持這一點。