簡體   English   中英

如何優化遞歸INSERT和SELECT DISTINCT mysql查詢

[英]How to optimize recursive INSERT and SELECT DISTINCT mysql query

我有兩個MySQL表WData-Clean和WData。 我在WData中導入數據,每次都有很多重復的記錄。 數據需要超時堆疊,因此無法刪除重復項。 在WData-Clean中,我導入WData中的所有“唯一”記錄。 此處示例中的唯一記錄是與某些字段可能具有相同值的所有其他類似記錄不同的記錄。

為此,我使用以下查詢:

INSERT INTO `WData-clean` (`field1`, `field2`, `field3`, `field4`, `field5`, `field6`) 
SELECT DISTINCT `field1`, `field2`, `field3`, `field4`, `field5`, `field6`
FROM WData cr
WHERE NOT EXISTS (SELECT * FROM `WData-clean` c
WHERE (cr.field1 = c.field1 AND cr.field2 = c.field2))

在WData累積了超過200萬條記錄之前,這種情況一直很有效,而且這個查詢確實很困難,因為它必須將每個提案與源表中的每個現有記錄進行比較。

如何優化此查詢的性能?

在編寫查詢以規范化數據時,應始終使用GROUP BY

INSERT INTO `WData-clean` (`field1`, `field2`, `field3`, `field4`, `field5`, `field6`) 
(
    SELECT
        `field1`,
        `field2`,
        `field3`,
        `field4`,
        `field5`,
        `field6`
    FROM
        WData AS cr
    WHERE NOT EXISTS (
        SELECT
            *
        FROM
            `WData-clean` AS c
        WHERE
            cr.field1 = c.field1
            AND cr.field2 = c.field2)
    )
    GROUP BY
        `field1`, `field2`, `field3`, `field4`, `field5`, `field6`
)

此外,它超出了這個問題的范圍(有點),但我試圖找到一種方法來避免WHERE NOT EXISTS 隨着WData-clean的增長,該查詢將開始花費更長的時間來匹配。

我可以想到3種方法:

  1. 在wdata_clean表中,在所有需要唯一的字段上創建唯一索引。 在wdata表中創建一個時間戳字段,用於記錄上次更改記錄的時間。 還存儲上次刷新wdata_clean時的時間戳。 然后使用INSERT IGNORE ... SELECT ...選擇自上次更新wdata_clean以來修改過的wdata記錄的where條件。 最后,更新上次同步的時間戳。

  2. 在wdata表中創建一個時間戳字段,在兩個表中創建一個varchar字段。 還存儲數據上次同步的時間戳。 在varchar字段中,計算必須唯一的所有字段的哈希值(例如sha1)。 insert ... select ...在哈希字段上的wdata_clean上執行左連接,為null:

    insert into wdata_clean select * from wdata left join wdata_clean on wdata.hashfield=wdata_clean.hashfield where wdata_clean.hashfield is null and wdata.timestampfield>'timestamp of last sync'

在wdata和wdata_clean表中的哈希字段的哈希和時間戳字段上創建復合索引。

  1. 在wdata_clean中創建一個哈希字段,如第二點所述,並在其上添加唯一索引。 將插入/更新/刪除觸發器添加到wdata。 在觸發器中,計算字段的哈希值是唯一的,並在wdata_cleaned表中insert ignore ...

您當前的查詢實際上對WData上的每一行執行一次子查詢(因為子查詢依賴於WData中的行)。

如果您在字段上有索引,我會根據可能匹配的字段執行簡單的LEFT OUTER JOIN,並檢查WHERE子句中找不到匹配的行: -

INSERT INTO WData-clean (field1, field2, field3, field4, field5, field6) 
SELECT DISTINCT cr.field1, cr.field2, cr.field3, cr.field4, cr.field5, cr.field6
FROM WData cr
LEFT OUTER JOIN WData-clean c
ON cr.field1 = c.field1 
AND cr.field2 = c.field2
WHERE c.field1 IS NULL

(此示例假定c.field1不能合法地具有NULL值 - 可能最好使用WData-clean表中的主鍵來避免此問題)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM