從具有許多 FOREIGN KEY 引用的表中優化單行 DELETE
在我正在處理的數據庫中,有一個名為
persons
大約一百萬行的表,以及來自其他表(一些具有數百萬行)的 60 個 FK (FK) 約束指向它。如果我從中刪除一行
persons
,則需要很多分鐘,這不是問題,但它也會使表保持鎖定狀態,從而阻止所有程序的數據庫。過去,這會導致使用者報告系統已關閉。當然,如果我為所有 FK 添加支持索引,情況會大大改善(目前,60 個表中只有 20 個有它)。但是這些 FK 中的許多都是針對類似 的列
modified_by
,因此所有索引都沒有其他用途,並且會降低系統在日常操作中的性能,只能在特殊情況下獲得改進。在執行 DELETE 之前,我已經確保所有引用行都已被刪除或更新。我是手動做的,因為我強烈反對使用 CASCADE。
我沒有考慮軟刪除,否則我將不得不更改所有讀取
persons
表的軟體以跳過已刪除的行。問題
有沒有辦法(可能暫時)改變
persons
表的鎖定機制,這樣即使 DELETE 需要一個小時,它也不會影響並發程序?注意事項
- 禁用 FK 可能是一種可能性。風險在於,當我刪除該行時,其他人會造成不一致,然後我無法重新啟用 FK。
- 要刪除的行:通常一次刪除一個。手動操作或計劃。
- 有趣的一點:我沒有立即查看執行計劃,但是很明顯,除了引用表的PK上的“Clustered index Scan (Clustered)”7例之外,幾乎所有操作的成本都是0%;其中一個成本為 57%,另一個從 1% 到 16%。我仍然不明白為什麼它應該掃描聚集索引。
如果我為所有 FK 添加支持索引,情況會大大改善(目前,60 個表中只有 20 個有它)
您應該始終索引用作鍵的欄位,無論是外鍵還是其他鍵。這在分析如何執行查詢時為數據庫提供了更多選擇,添加它們實際上可能會提高應用程序的整體性能。
其中許多 FK 用於“修改者”之類的列,因此所有索引都沒有其他用途
與
$$ pretty much $$行星數據庫上的所有內容,這是一種妥協。
在這裡,您正在平衡數據完整性 - 確定誰更改了某些內容 - 與速度 - 沒有那些會減慢插入速度的額外索引。如果您不知道(確定地)更改這些記錄的使用者,這真的很重要嗎?如果沒有,你就可以了。如果它確實很重要——而且在很多情況下,它真的很重要——那麼你就會被索引的成本所困擾。
在執行 DELETE 之前,我已經確保所有引用記錄都已被刪除……
有了 FK,你無論如何都不能刪除它們,所以這個活動的價值是可疑的。
問題應該是,為什麼刪除需要一個小時?
如果您只刪除一百萬行表中的一條記錄,並且表中沒有 FK 回到該表的行,那麼要花什麼時間呢?它實際上應該是瞬時的。
查詢緩慢,甚至刪除,通常是由於缺少索引造成的——您是否根據記錄的主鍵欄位執行刪除?或者其他一些組合
$$ not-indexed $$領域?