文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  DELETE 語法

15.2.2 DELETE 語法

DELETE 是一個 DML 語法,用於從資料表中移除資料列。

DELETE 語法可以從 WITH 子句開始,以定義 DELETE 內可存取的通用資料表運算式。請參閱第 15.2.20 節,「WITH (通用資料表運算式)」

單一資料表語法

DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [[AS] tbl_alias]
    [PARTITION (partition_name [, partition_name] ...)]
    [WHERE where_condition]
    [ORDER BY ...]
    [LIMIT row_count]

DELETE 語法會從 tbl_name 刪除資料列,並傳回刪除的資料列數。若要檢查刪除的資料列數,請呼叫ROW_COUNT() 函數,如第 14.15 節,「資訊函數」所述。

主要子句

選用的 WHERE 子句中的條件會識別要刪除的資料列。如果沒有 WHERE 子句,則會刪除所有資料列。

where_condition 是一個運算式,會針對每個要刪除的資料列評估為 true。其指定方式如第 15.2.13 節,「SELECT 語法」所述。

如果指定了 ORDER BY 子句,則會依指定的順序刪除資料列。LIMIT 子句會限制可以刪除的資料列數。這些子句適用於單一資料表刪除,但不適用於多資料表刪除。

多資料表語法

DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
    tbl_name[.*] [, tbl_name[.*]] ...
    FROM table_references
    [WHERE where_condition]

DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
    FROM tbl_name[.*] [, tbl_name[.*]] ...
    USING table_references
    [WHERE where_condition]

權限

您需要資料表的 DELETE 權限才能從中刪除資料列。您只需要讀取任何資料行的 SELECT 權限,例如 WHERE 子句中指定的那些資料行。

效能

當您不需要知道刪除的資料列數時,TRUNCATE TABLE 語法是清空資料表的更快方式,而不是沒有 WHERE 子句的 DELETE 語法。與 DELETE 不同,TRUNCATE TABLE 無法在交易中使用,或者當您鎖定資料表時也無法使用。請參閱第 15.1.37 節,「TRUNCATE TABLE 語法」第 15.3.6 節,「LOCK TABLES 和 UNLOCK TABLES 語法」

刪除操作的速度也可能受到第 10.2.5.3 節,「最佳化 DELETE 語法」中所討論的因素影響。

為確保指定的 DELETE 語法不會花費太多時間,MySQL 特有的 LIMIT row_count 子句適用於 DELETE,用於指定要刪除的最大資料列數。如果要刪除的資料列數大於限制,請重複 DELETE 語法,直到受影響的資料列數小於 LIMIT 值。

子查詢

您無法在子查詢中從資料表刪除資料並從同一個資料表選取資料。

分割資料表支援

DELETE 支援使用 PARTITION 子句明確選取分割區,該子句會採用以逗號分隔的一或多個分割區或子分割區 (或兩者) 的名稱清單,從中選取要捨棄的資料列。清單中未包含的分割區會被忽略。假設有一個名為 p0 的分割區分割資料表 t,執行 DELETE FROM t PARTITION (p0) 語法對於資料表的影響,與執行 ALTER TABLE t TRUNCATE PARTITION (p0) 相同;在這兩種情況下,都會捨棄分割區 p0 中的所有資料列。

PARTITION 可以與 WHERE 條件搭配使用,在此情況下,只會在列出的分割區中的資料列上測試該條件。例如,DELETE FROM t PARTITION (p0) WHERE c < 5 只會從條件 c < 5 為 true 的分割區 p0 中刪除資料列;任何其他分割區中的資料列都不會檢查,因此不受 DELETE 的影響。

PARTITION 子句也可以在多資料表 DELETE 語法中使用。您可以在 FROM 選項中命名的每個資料表使用最多一個此類選項。

如需更多資訊和範例,請參閱第 26.5 節,「分割區選取」

自動遞增資料行

如果您刪除包含 AUTO_INCREMENT 資料行最大值的資料列,該值不會重複用於 MyISAMInnoDB 資料表。如果您在 autocommit 模式下,使用 DELETE FROM tbl_name (沒有 WHERE 子句) 刪除資料表中的所有資料列,除了 InnoDBMyISAM 以外,所有儲存引擎的序列都會重新開始。對於 InnoDB 資料表,此行為有一些例外情況,如第 17.6.1.6 節,「InnoDB 中的 AUTO_INCREMENT 處理」所述。

對於 MyISAM 資料表,您可以在多資料行索引鍵中指定 AUTO_INCREMENT 次要資料行。在此情況下,即使對於 MyISAM 資料表,也會重複使用從序列頂端刪除的值。請參閱第 5.6.9 節,「使用 AUTO_INCREMENT」

修飾詞

DELETE 語法支援下列修飾詞

  • 如果您指定 LOW_PRIORITY 修飾詞,伺服器會延遲執行 DELETE,直到沒有其他用戶端正在從資料表讀取資料為止。這只會影響僅使用資料表層級鎖定的儲存引擎 (例如 MyISAMMEMORYMERGE)。

  • 對於 MyISAM 資料表,如果您使用 QUICK 修飾詞,儲存引擎在刪除期間不會合併索引葉節點,這可能會加快某些刪除操作的速度。

  • IGNORE 修飾詞會使 MySQL 在刪除資料列的過程中忽略可忽略的錯誤。(在剖析階段遇到的錯誤會以通常方式處理。)由於使用 IGNORE 而忽略的錯誤會以警告形式傳回。如需更多資訊,請參閱IGNORE 對語法執行的影響

刪除順序

如果 DELETE 語法包含 ORDER BY 子句,則會依子句指定的順序刪除資料列。這主要與 LIMIT 搭配使用很有用。例如,以下語法會尋找符合 WHERE 子句的資料列,依 timestamp_column 排序,並刪除第一個 (最舊的) 資料列

DELETE FROM somelog WHERE user = 'jcole'
ORDER BY timestamp_column LIMIT 1;

ORDER BY 也有助於依照避免參考完整性違規所需的順序刪除資料列。

InnoDB 資料表

如果您要從大型資料表中刪除許多資料列,可能會超過 InnoDB 資料表的鎖定資料表大小。為了避免此問題,或只是為了盡量減少資料表保持鎖定的時間,下列策略 (完全不使用 DELETE) 可能會有幫助

  1. 選取要刪除的資料列到與原始資料表結構相同的空資料表中

    INSERT INTO t_copy SELECT * FROM t WHERE ... ;
  2. 使用 RENAME TABLE 以原子方式移出原始資料表,並將複本重新命名為原始名稱

    RENAME TABLE t TO t_old, t_copy TO t;
  3. 捨棄原始資料表

    DROP TABLE t_old;

RENAME TABLE 執行時,其他工作階段無法存取所涉及的資料表,因此重新命名操作不會受到並行問題的影響。請參閱第 15.1.36 節,「RENAME TABLE 語法」

MyISAM 資料表

MyISAM 資料表中,刪除的資料列會維護在連結清單中,而後續的 INSERT 操作會重複使用舊的資料列位置。若要回收未使用的空間並減少檔案大小,請使用 OPTIMIZE TABLE 語法或 myisamchk 公用程式來重新組織資料表。OPTIMIZE TABLE 更易於使用,但 myisamchk 速度更快。請參閱第 15.7.3.4 節,「OPTIMIZE TABLE 語法」第 6.6.4 節,「myisamchk — MyISAM 資料表維護公用程式」

QUICK 修飾詞會影響是否合併刪除操作的索引葉節點。DELETE QUICK 最適用於刪除資料列的索引值由稍後插入的資料列中的類似索引值取代的應用程式。在此情況下,會重複使用已刪除值所留下的間隙。

當已刪除的值導致未填滿的索引區塊跨越索引值的範圍 (會再次發生新的插入) 時,DELETE QUICK 並沒有用處。在此情況下,使用 QUICK 可能會導致索引中浪費空間,且該空間仍未回收。以下是這種情況的範例

  1. 建立一個包含索引 AUTO_INCREMENT 資料行的資料表。

  2. 將許多資料列插入資料表中。每個插入都會導致索引值加入索引的高端。

  3. 使用 DELETE QUICK 刪除資料行範圍低端的資料列區塊。

在這個情境中,與已刪除索引值相關聯的索引區塊會變得空間不足,但由於使用了 QUICK,因此不會與其他索引區塊合併。當有新的插入發生時,它們仍會保持空間不足的狀態,因為新列沒有已刪除範圍內的索引值。此外,即使您稍後使用不含 QUICKDELETE,它們仍會保持空間不足,除非某些已刪除的索引值恰好位於空間不足區塊內或相鄰的索引區塊中。若要在此情況下回收未使用的索引空間,請使用 OPTIMIZE TABLE

如果要從表格中刪除大量列,使用 DELETE QUICK 後再使用 OPTIMIZE TABLE 可能會更快。這會重建索引,而不是執行許多索引區塊合併操作。

多表格刪除

您可以在 DELETE 陳述式中指定多個表格,以根據 WHERE 子句中的條件從一個或多個表格中刪除列。您無法在多表格的 DELETE 中使用 ORDER BYLIMITtable_references 子句列出聯結中涉及的表格,如 15.2.13.2 節,「JOIN 子句」中所述。

對於第一個多表格語法,只會刪除 FROM 子句之前列出的表格中符合條件的列。對於第二個多表格語法,只會刪除 FROM 子句(USING 子句之前)中列出的表格中符合條件的列。其效果是,您可以同時從多個表格中刪除列,並擁有僅用於搜尋的其他表格。

DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3
WHERE t1.id=t2.id AND t2.id=t3.id;

或者

DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3
WHERE t1.id=t2.id AND t2.id=t3.id;

這些陳述式在搜尋要刪除的列時會使用所有三個表格,但只會從表格 t1t2 中刪除符合條件的列。

前面的範例使用 INNER JOIN,但多表格的 DELETE 陳述式可以使用 SELECT 陳述式中允許的其他聯結類型,例如 LEFT JOIN。例如,若要刪除存在於 t1 中但在 t2 中沒有匹配項的列,請使用 LEFT JOIN

DELETE t1 FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;

為了與 Access 相容,語法允許在每個 tbl_name 後面加上 .*

如果您使用涉及 InnoDB 表格的多表格 DELETE 陳述式,且這些表格具有外鍵約束,則 MySQL 優化器可能會以與其父/子關係不同的順序處理表格。在這種情況下,陳述式會失敗並回滾。您應該改為從單個表格中刪除,並依賴 InnoDB 提供的 ON DELETE 功能,以使其他表格也能相應地被修改。

注意

如果您為表格宣告別名,則在引用該表格時必須使用別名。

DELETE t1 FROM test AS t1, test2 WHERE ...

多表格 DELETE 中的表格別名應該只在陳述式的 table_references 部分中宣告。在其他地方,允許使用別名引用,但不允許宣告別名。

正確

DELETE a1, a2 FROM t1 AS a1 INNER JOIN t2 AS a2
WHERE a1.id=a2.id;

DELETE FROM a1, a2 USING t1 AS a1 INNER JOIN t2 AS a2
WHERE a1.id=a2.id;

不正確

DELETE t1 AS a1, t2 AS a2 FROM t1 INNER JOIN t2
WHERE a1.id=a2.id;

DELETE FROM t1 AS a1, t2 AS a2 USING t1 INNER JOIN t2
WHERE a1.id=a2.id;

單表格 DELETE 陳述式也支援表格別名。