簡體   English   中英

為什么使用子查詢進行 DELETE 比使用簡單的 ID 列表慢得多?

[英]Why DELETE with subquery is much slower than with simple list of IDs?

我想根據主鍵從中等大小 (700K) 表中刪除大量行。 認為,最好的方法應該使用SELECT -subquery 來DELETE源列表。 並在這里找到了具體的答案 問題是:它比使用兩個單獨的查詢慢得多(首先選擇 ID,然后從表中刪除這些 ID)。 為什么呢?

我也做了簡單的測試用例:

CREATE TABLE `xyz` (
  `xyzID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `col1` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`xyzID`)
) ENGINE=InnoDB;

用百萬條記錄填充它,然后:

DELETE FROM xyz
WHERE xyzID IN
        (
        SELECT xyzID
        FROM
            (
                SELECT xyzID
                FROM xyz
                LIMIT 3000,1000
            ) a
        );
Query OK, 1000 rows affected (53.52 sec)

刪除 2000 行會使時間加倍:

Query OK, 2000 rows affected (1 min 48.25 sec)

但是刪除沒有子查詢(首先選擇)幾乎沒有時間(隨機生成的id列表,在這里):

DELETE FROM test.xyz WHERE xyzID IN ( 660422,232794,573802,....
Query OK, 996 rows affected (0.04 sec)

為什么用子查詢刪除這么慢?

如果您閱讀有關子查詢的文檔,您會發現一些可能導致此問題的原因: https : //dev.mysql.com/doc/refman/5.7/en/subquery-restrictions.html

優化器將使用exists將不相關的WHERE IN (Subquery)語句重寫為相關語句。

因此,您的查詢實際上可能是這樣執行的:

DELETE FROM xyz t1
WHERE EXISTS (
    (
    SELECT 1
    FROM
        (
            SELECT xyzID t3
            FROM xyz
            LIMIT 3000,1000
        ) a
    where t1.xyzID = a.xyzID
    );

現在每次刪除一行時都需要執行相關子查詢。

所以:對於 1000 次刪除,您將在臨時表a上運行 1000 個子查詢。 只有內部查詢將保持不相關。

in(valuelist)相比,您正在運行1001查詢而不是1

文檔:

這意味着 IN 子查詢可能比使用 IN(value_list) 運算符編寫的查詢慢得多,該運算符列出子查詢將返回的相同值。

解決這個問題的第一步是選擇要刪除的id到一個臨時表中。 但是,當您嘗試實際執行刪除操作時,您可能仍會遇到慢子查詢問題。

解決方案是使用DELETE xyz FROM xyz INNER JOIN xyz_temp WHERE xyz.id = xyz_temp.id語法,它實現了相同的事情並且運行速度與簡單連接一樣快。

子查詢意味着您要求數據庫引擎將第一個表中的所有“N”行與您當時正在創建的另一個表中的所有“M”行進行比較。 這意味着你有 N*M 比較操作,要做到這一點,你需要加入表。 您正在構建的表有 N * M 行。

如果沒有子查詢,您只是將表中的所有“N”行與“X”關鍵字進行比較,其中“X”<<“M”。

暫無
暫無

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

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