Sql-Server

SQL Server 如何處理 DELETE WHERE EXISTS (SELECT 1 FROM TABLE)?

  • January 18, 2021

下面是一個有效的 TSQL 語句。但我想了解 SQL Server 是如何處理它的。

DELETE A
FROM table1 WITH (NOLOCK)
WHERE
   EXISTS
   (
   SELECT 1
   FROM
       table2 B WITH (NOLOCK)
   WHERE
       B.id = A.id
   )

因為子查詢的輸出將是一個 1 的列表。SQL Server 如何知道要刪除哪些行?

SQL Server 如何知道要刪除哪些行?

要了解它的處理方式,查看查詢的執行計劃可能更有幫助。安裝腳本在最後。

首先,讓我們將查詢稍微更改為應該引發錯誤但不會引發錯誤的內容。

DELETE A
FROM table1 AS A
WHERE EXISTS
(
   SELECT 1/0
   FROM table2 B
   WHERE B.id = A.id
);

如果你只是執行SELECT 1/0,你會得到一個除以零的錯誤。但是有些地方表達式存在於 parsing 查詢中,但優化器實際上並未投影。

您所指的“列表”從未真正出現過。辨識要刪除的行的所有工作都是通過exists中的**where子句完成的。

當您需要了解數據流向時,從右到左閱讀計劃是正確的方法。從左到右是邏輯流。

堅果

我們有:

  • 兩個表的完整掃描
  • 用於匹配行的雜湊聯接
  • 刪除自table1

堅果

散列連接計算出需要刪除的行,並將符合條件的書籤值傳遞給刪除運算符。在這種情況下,書籤用於唯一標識行,因為沒有可用於從中使用的聚集索引。

使用唯一的聚集索引,可以單獨使用鍵值來標識行。對於非唯一聚集索引,任何重複值都會附帶一個額外的唯一標識符,儘管這對您來說是不可見的。

設置腳本

DROP TABLE IF EXISTS table1, table2;

CREATE TABLE dbo.table1 (id int NOT NULL);
CREATE TABLE dbo.table2 (id int NOT NULL);

INSERT 
   dbo.table1 WITH(TABLOCK) (id) 
SELECT 
   x.*
FROM 
(
   SELECT 
       ROW_NUMBER() OVER(ORDER BY 1/0) AS n 
   FROM sys.messages AS m
) AS x;

INSERT 
   dbo.table2 WITH(TABLOCK) (id)
SELECT 
   t.*
FROM dbo.table1 AS t
WHERE id % 2 = 0;

SELECT TOP (100) t1.* FROM dbo.table1 AS t1;
SELECT TOP (100) t2.* FROM dbo.table2 AS t2;

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