我有一个连接查询
Select E.Id,E.Name from Employee E join Dept D on E.DeptId=D.Id
和子查询查询
Select E.Id,E.Name from Employee Where DeptId in (Select Id from Dept)
哪个会更快,为什么?
我什么时候应该选择其中一种而不是另一种?
嗯,我相信这是一个“古老但黄金”的问题。答案是:“这要看情况!”。 性能是一个如此微妙的主题,以至于说“永远不要使用子查询,总是加入”就太愚蠢了。 在以下链接中,您将找到一些我认为非常有帮助的基本最佳实践:
我有一个包含 50000 个元素的表,我要查找的结果是 739 个元素。
我最初的疑问是这样的:
SELECT p.id,
p.fixedId,
p.azienda_id,
p.categoria_id,
p.linea,
p.tipo,
p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND p.anno = (
SELECT MAX(p2.anno)
FROM prodotto p2
WHERE p2.fixedId = p.fixedId
)
执行时间为7.9秒。
我最后的查询是这样的:
SELECT p.id,
p.fixedId,
p.azienda_id,
p.categoria_id,
p.linea,
p.tipo,
p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND (p.fixedId, p.anno) IN
(
SELECT p2.fixedId, MAX(p2.anno)
FROM prodotto p2
WHERE p.azienda_id = p2.azienda_id
GROUP BY p2.fixedId
)
花费了0.0256s
好 SQL,好。
我希望第一个查询会更快,主要是因为您有一个等价项和一个显式 JOIN。根据我的经验,
IN
是一个非常慢的运算符,因为 SQL 通常将其评估为一系列由“OR”分隔的WHERE
子句 (WHERE x=Y OR x=Z OR...
)。
与 ALL THINGS SQL 一样,您的情况可能会有所不同。速度在很大程度上取决于索引(您的两个 ID 列上都有索引吗?这将有很大帮助......)。
百分百确定哪个更快的唯一真正方法是打开性能跟踪(IO 统计特别有用)并运行它们。确保在运行之间清除缓存!
性能取决于您正在执行的数据量...
如果数据较少的话20k左右。加入效果更好。
如果数据更像 100k+,那么 IN 效果更好。
如果您不需要其他表中的数据,IN 很好,但最好选择 EXISTS。
我测试了所有这些标准,并且表格具有正确的索引。
开始查看执行计划,看看 SQl Server 如何解释它们的差异。您还可以使用 Profiler 多次实际运行查询并获取差异。
我不希望它们有如此大的不同,当您使用相关子查询时,使用连接而不是子查询可以获得真正的、巨大的性能提升。
EXISTS 通常比这两者中的任何一个都更好,当您谈论左连接时,您想要不在左连接表中的所有记录,那么 NOT EXISTS 通常是更好的选择。
性能应该是一样的;在表上应用正确的索引和集群更为重要(关于该主题存在一些好的资源)。
(编辑以反映更新的问题)
我知道这是一篇旧文章,但我认为这是一个非常重要的话题,尤其是现在我们拥有 10M+ 记录并谈论 TB 级数据。
我还将强调以下观察结果。我的表 ([data]) 中有大约 45M 条记录,[cats] 表中有大约 300 条记录。我对我要讨论的所有查询都有广泛的索引。
考虑示例 1:
UPDATE d set category = c.categoryname
FROM [data] d
JOIN [cats] c on c.id = d.catid
与示例 2 相比:
UPDATE d set category = (SELECT TOP(1) c.categoryname FROM [cats] c where c.id = d.catid)
FROM [data] d
示例 1 的运行时间约为 23 分钟。示例 2 大约需要 5 分钟。
所以我得出结论,在这种情况下子查询要快得多。当然,请记住,我使用的 M.2 SSD 驱动器具有 I/O @ 1GB/秒(这是字节而不是位),因此我的索引也非常快。因此,这也可能会影响您的情况下的速度
如果是一次性数据清理,最好让它运行并完成。我使用 TOP(10000) 并查看在执行大查询之前需要多长时间并乘以记录数。
如果您正在优化生产数据库,我强烈建议对数据进行预处理,即使用触发器或作业代理来异步更新记录,以便实时访问检索静态数据。
这两个查询在语义上可能不相同。如果一名员工为多个部门工作(可能在我工作的企业中;不可否认,这意味着您的表未完全规范化),那么第一个查询将返回重复的行,而第二个查询则不会。为了使这种情况下的查询等效,必须将
DISTINCT
关键字添加到 SELECT
子句中,这可能会对性能产生影响。
请注意,有一个设计经验法则,规定表应该对实体/类或实体/类之间的关系进行建模,但不能同时对两者进行建模。因此,我建议您创建第三个表,例如
OrgChart
,来模拟员工和部门之间的关系。
您可以使用解释计划来获得客观答案。
对于您的问题,“存在”过滤器可能执行速度最快。