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

a_s*_*hie 3 sql-server delete t-sql exists

下面是一个有效的 TSQL 语句。但我想了解 SQL Server 如何处理它。

DELETE A
FROM table1 WITH (NOLOCK)
WHERE
    EXISTS
    (
    SELECT 1
    FROM
        table2 B WITH (NOLOCK)
    WHERE
        B.id = A.id
    )
Run Code Online (Sandbox Code Playgroud)

因为子查询的输出将是一个 1 的列表。SQL Server 如何知道要删除哪些行?

Eri*_*ing 12

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

要了解它是如何处理的,查看查询的执行计划可能更有帮助。安装脚本在最后。

首先,让我们将查询稍微更改为应该引发错误但不会引发错误的内容。

DELETE A
FROM table1 AS A
WHERE EXISTS
(
    SELECT 1/0
    FROM table2 B
    WHERE B.id = A.id
);
Run Code Online (Sandbox Code Playgroud)

如果你只是运行,SELECT 1/0你会得到一个除以零的错误。但是有些地方在解析查询中存在表达式,但实际上并没有被优化器投影。

您所指的“列表”从未真正出现过。标识要删除的行的所有工作都是通过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;
Run Code Online (Sandbox Code Playgroud)