我想知道我是否有类似这样的连接查询 -
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)
当我考虑性能时,这两个查询中的哪一个会更快,为什么?
还有什么时候我应该更喜欢一个而不是另一个?
抱歉,如果这太琐碎并且之前问过,但我对此感到困惑。此外,如果你们能向我推荐我应该用来衡量两个查询性能的工具,那就太好了。非常感谢!
我希望第一个查询更快,主要是因为你有一个等价和一个明确的 JOIN。根据我的经验,IN
是一个非常慢的运算符,因为 SQL 通常将它评估为一系列由“OR”(WHERE x=Y OR x=Z OR...
) 分隔的 WHERE
子句。
不过,与 ALL THINGS SQL 一样,您的里程可能会有所不同。速度在很大程度上取决于索引(您在两个 ID 列上都有索引吗?这将有很大帮助......)等等。
100% 确定哪个更快的唯一真正方法是打开性能跟踪(IO 统计特别有用)并同时运行它们。确保在运行之间清除缓存!
好吧,我相信这是一个“古老但黄金”的问题。答案是:“这取决于!”。表演是一个如此微妙的主题,以至于说“永远不要使用子查询,总是加入”就太愚蠢了。在以下链接中,您将找到一些我认为非常有用的基本最佳实践:
优化子查询
使用半连接转换优化子查询
将子查询重写为连接
我有一个包含 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,很好。
性能取决于您正在执行的数据量......
如果是20k左右的数据较少。加入效果更好。
如果数据更像 100k+,那么 IN 效果更好。
如果您不需要其他表中的数据,IN 很好,但最好选择 EXISTS。
我测试的所有这些标准和表格都有适当的索引。
开始查看执行计划以了解 SQl 服务器如何解释它们的差异。您还可以使用 Profiler 多次实际运行查询并获得差异。
我不希望这些有如此可怕的不同,当您使用相关子查询时,您可以在使用连接而不是子查询时获得真正的、巨大的性能提升。
EXISTS 通常比这两者中的任何一个都好,当您谈论左连接时,您想要所有不在左连接表中的记录,那么 NOT EXISTS 通常是一个更好的选择。
我知道这是一篇旧文章,但我认为这是一个非常重要的话题,尤其是现在我们有 1000 万多条记录并谈论 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 驱动器能够以 1GB/秒的速度进行 i/o(这是字节而不是位),因此我的索引也非常快。因此,在您的情况下,这也可能会影响速度
如果它是一次性的数据清理,最好让它运行并完成。我使用 TOP(10000) 并查看在进行大查询之前需要多长时间并乘以记录数。
如果您正在优化生产数据库,我强烈建议您对数据进行预处理,即使用触发器或工作代理来异步更新记录,以便实时访问检索静态数据。
这两个查询在语义上可能不等效。如果员工为多个部门工作(可能在我工作的企业中;诚然,这意味着您的表没有完全规范化),那么第一个查询将返回重复的行,而第二个查询则不会。在这种情况下,要使查询等效,必须将 DISTINCT
关键字添加到 SELECT
子句,这可能会影响性能。
请注意,有一条设计经验法则指出,表应该对实体/类或实体/类之间的关系进行建模,但不能同时对两者进行建模。因此,我建议您创建第三个表,例如 OrgChart
,以模拟员工和部门之间的关系。
您可以使用解释计划来获得客观的答案。
对于您的问题,an Exists filter 可能执行得最快。