Mic*_*son 88 join sql-server exists
使用 LEFT JOIN 或 NOT EXISTS 格式之间是否有最佳实践?
使用一个比另一个有什么好处?
如果没有,应该首选哪个?
SELECT *
FROM tableA A
LEFT JOIN tableB B
ON A.idx = B.idx
WHERE B.idx IS NULL
Run Code Online (Sandbox Code Playgroud)
SELECT *
FROM tableA A
WHERE NOT EXISTS
(SELECT idx FROM tableB B WHERE B.idx = A.idx)
Run Code Online (Sandbox Code Playgroud)
我在 Access 中对 SQL Server 数据库使用查询。
Han*_*non 68
最大的区别是不是在加入VS不存在,它是(书面),该SELECT *。
在第一个例子中,你得到的所有列都 A和B,而在第二个例子,你从只列A。
在 SQL Server 中,在一个非常简单的人为示例中,第二个变体稍微快一点:
创建两个示例表:
CREATE TABLE dbo.A
(
A_ID INT NOT NULL
PRIMARY KEY CLUSTERED
IDENTITY(1,1)
);
CREATE TABLE dbo.B
(
B_ID INT NOT NULL
PRIMARY KEY CLUSTERED
IDENTITY(1,1)
);
GO
Run Code Online (Sandbox Code Playgroud)
在每个表中插入 10,000 行:
INSERT INTO dbo.A DEFAULT VALUES;
GO 10000
INSERT INTO dbo.B DEFAULT VALUES;
GO 10000
Run Code Online (Sandbox Code Playgroud)
从第二个表中每 5 行删除一次:
DELETE
FROM dbo.B
WHERE B_ID % 5 = 1;
SELECT COUNT(*) -- shows 10,000
FROM dbo.A;
SELECT COUNT(*) -- shows 8,000
FROM dbo.B;
Run Code Online (Sandbox Code Playgroud)
执行两个测试SELECT语句变体:
SELECT *
FROM dbo.A
LEFT JOIN dbo.B ON A.A_ID = B.B_ID
WHERE B.B_ID IS NULL;
SELECT *
FROM dbo.A
WHERE NOT EXISTS (SELECT 1
FROM dbo.B
WHERE b.B_ID = a.A_ID);
Run Code Online (Sandbox Code Playgroud)
执行计划:
第二个变体不需要执行过滤操作,因为它可以使用左反半连接运算符。
Rob*_*ley 31
从逻辑上讲,它们是相同的,但NOT EXISTS更接近您要求的 AntiSemiJoin,并且通常是首选。它还更好地强调了您无法访问 B 中的列,因为它仅用作过滤器(而不是让它们具有 NULL 值)。
许多年前(SQL Server 6.0 ish)LEFT JOIN速度更快,但很长一段时间以来情况并非如此。这些天,NOT EXISTS速度略快。
Access 中最大的影响是该JOIN方法必须在过滤之前完成联接,在内存中构造联接集。使用NOT EXISTS它检查行但不为列分配空间。另外,一旦找到一行,它就会停止查找。Access 中的性能变化更大一些,但一般的经验法则是,它NOT EXISTS往往会更快一些。我不太愿意说这是“最佳实践”,因为涉及的因素更多。
我注意到的一个例外是使用Linked Servers时的NOT EXISTS优越性(但略有不同)。LEFT JOIN ... WHERE IS NULL
从检查执行计划来看,NOT EXISTS运算符似乎是以嵌套循环方式执行的。因此它是按行执行的(我认为这是有道理的)。
通常,引擎将创建一个基本上基于以下内容的执行计划:
对于(4):
“不存在”计划鼓励在表 B 上进行基于查找的计划。当表 A 小而表 B 大(并且索引存在于 B 上)时,这是一个不错的选择。
当表 A 非常大或表 B 非常小或 B 上没有索引并返回大结果集时,“反联接”计划是一个不错的选择。
然而,它只是一种“鼓励”,就像加权输入一样。强 (1)、(2)、(3) 常常使选择 (4) 没有实际意义。
(忽略您的示例由于 * 返回不同列的影响,由@MaxVernon 回答解决。)。
| 归档时间: |
|
| 查看次数: |
183193 次 |
| 最近记录: |