T-Sql

SQL Server 會在單個 DELETE 語句中檢查行刪除之間的 FK 限制嗎?

  • November 12, 2020

我有一個自引用的表:

CREATE TABLE [dbo].[TestTable] (
   [id] [bigint] IDENTITY(100000,1) NOT NULL,
   [referenced_id] [bigint] NULL,
   CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED (
       [id] ASC
   ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE [dbo].[TestTable] WITH NOCHECK ADD CONSTRAINT [FK_ReferencedId] FOREIGN KEY ([referenced_id])
   REFERENCES [dbo].[TestTable] ([id])
GO

ALTER TABLE [dbo].[TestTable] CHECK CONSTRAINT [FK_ReferencedId]
GO

假設我有幾行相互引用:

id     | referenced_id
-------|--------------
100023 | 100024
100024 | 100023
100025 | 100026
100026 | 100023

如果我嘗試DELETE使用該行WHERE [id] = 100023,則 FK 將被違反,因為100024100026引用該行並且該DELETE行將失敗。但是,如果我只是DELETE FROM [dbo].[TestTable],它似乎可以工作並成功刪除所有行。因此,SQL Server 似乎只在單個DELETE語句中要刪除的所有行都被刪除之後才檢查 FK 約束,而不是在每行刪除之間。

我可以依靠這種行為,還是DELETE有時會失敗?

SQL Server 似乎僅在刪除單個 DELETE 語句中要刪除的所有行之後才檢查 FK 約束,而不是在每行刪除之間。我可以依靠這種行為嗎?

是的。檢查語句的約束,而不是每一行,也不是在事務結束時檢查。

這是從該表中刪除的查詢計劃。

在此處輸入圖像描述

刪除發生在頂部分支上,但已刪除行的 ID 是假離線的,並且在聚集索引刪除步驟之後,假離線 ID 用於查找引用已刪除行的任何行。如果發現任何一個 DELETE 將被回滾(DML 語句總是在內部的嵌套事務中執行),並引發 FK 錯誤。

引用自:https://dba.stackexchange.com/questions/279579