[英]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.