0

我正在尋找從我的數據庫中刪除重複記錄的有效方法。首先,我使用了一個使用連接等的存儲過程,這導致查詢執行非常緩慢。現在,我正在嘗試一種不同的方法。請考慮以下查詢:從數百萬條記錄中刪除重複行的有效方法

/* QUERY A */ 

SELECT * 
FROM my_table 
WHERE col1 = value 
    AND col2 = value 
    AND col3 = value 

此查詢僅在12秒內執行,結果爲182.400條記錄。表中的行數目前爲420.930.407,col1和col3爲索引。

下一個查詢:

/* QUERY B */ 

WITH ALL_RECORDS AS 
    (SELECT id 
    FROM my_table 
    WHERE col1 = value 
    AND col2 = value 
    AND col3 = value) 
SELECT * 
FROM ALL_RECORDS 

這個查詢用了不到2秒,並給我的182.400記錄在表中的所有ID的(根據where子句)。

然後,我的最後一次查詢,是選擇對我想組的列分組中的所有記錄最低(第一)的識別碼,以檢查重複的查詢:再次

/* QUERY C */ 

SELECT MIN(id) 
FROM my_table 
WHERE col1 = value 
    AND col2 = value 
    AND col3 = value 
GROUP BY col1, 
     col2, 
     col3, 
     col4, 
     col5, 
     col6 

,這個查詢執行在不到2秒內。結果是30.400,這意味着在獨特的182.400條記錄中有30.400條獨特記錄。

現在,我想刪除(或者,首先選擇以確保我有我的查詢權限)所有不是唯一的記錄。所以,我想從my_table中刪除182.400 - 30.400 = 152.000條記錄。

我想我會結合最後兩個查詢:根據col1,col2和col3(查詢B)的where子句獲取屬於我的數據集的所有id,然後從該數據集中刪除/選擇所有記錄該ID不在唯一記錄標識的ID列表中(查詢C)。

但是,當我從查詢B中選擇所有查詢B.id NOT IN查詢C時,查詢不需要2,4或12(14或16)秒,但似乎需要永遠(在後顯示20.000條記錄1分鐘,2分鐘後約爲40.000,所以我取消了查詢,因爲它會找到152.000條記錄,這將花費8分鐘)。

WITH ALL_RECORDS AS 
    (SELECT id 
    FROM my_table 
    WHERE col1 = value 
    AND col2 = value 
    AND col3 = value) 
SELECT id 
FROM ALL_RECORDS 
WHERE id NOT IN 
    (SELECT MIN(id) 
    FROM my_table 
    WHERE col1 = value 
     AND col2 = value 
     AND col3 = value 
    GROUP BY col1, 
       col2, 
       col3, 
       col4, 
       col5, 
       col6) 

我知道NOT IN是緩慢的,但我不能掌握它是如何的這種緩慢的(因爲沒有不參與各不超過2秒執行這兩個查詢)。

有沒有人對我如何解決這個難題有一些很好的建議?

------------------更多信息------------------

以前的解決方案是遵循存儲過程。出於某種原因,它在我的接受環境中完美執行,但不在我的生產環境中執行。目前,我們有超過4億的產量記錄和超過200萬條記錄被接受,所以這可能是一個原因。

DELETE my_table 
FROM my_table 
LEFT OUTER JOIN 
    (SELECT MIN(id) AS RowId, 
      col1, 
      col2, 
      col3, 
      col4, 
      col5, 
      col6 
    FROM my_table 
    WHERE col1 = value 
    AND col2 = value 
    AND col3 = value 
    GROUP BY col1, 
      col2, 
      col3, 
      col4, 
      col5, 
      col6) AS KeepRows ON my_table.id = KeepRows.RowId 
WHERE KeepRows.RowId IS NULL 
    AND my_table.col1 = value 
    AND my_table.col2 = value 
    AND my_table.col3 = value 

我已經基於計算器另一個答案該解決方案(不能在此刻找到它),但我覺得我應該能夠創建基於查詢B和C內的幾個執行查詢秒...

回答

1
with dupl as (
select row_number() over(partition by col1,col2,col3,col4,col5,col6 order by id) rn, 
id,col1,col2,col3,col4,col5,col6 
from myTable 
) 
delete dupl where rn>1 
+0

這似乎工作得非常快,謝謝!我會盡力實施它明天,並希望它會運行在生產以及:) – Tjab

1

將兩個2秒查詢結合在一起通常不會導致單個4秒查詢,因爲查詢與其基礎表不同,因爲查詢與其基礎表很少有關。

這類任務通常的做法是相應緩存要保持在一個臨時表id的,指數,然後在使用它left join(或not in - 我敢打賭,導致執行計劃實際上是相同的)。

如果您將使用主表上的索引,您可能會獲得更多的性能。例如,我認爲(col1, col2, col3)應該給你的代碼一些提升(列不應該按順序提及,它通常取決於它們的基數)。

+0

謝謝你的評論。雖然Alex的解決方案在工作,並且比在臨時表中緩存更簡單,但它的確讓我更好地理解如何處理查詢。 – Tjab