子选择与外部联接
考虑以下两个查询:
select tblA.a,tblA.b,tblA.c,tblA.d from tblA where tblA.a not in (select tblB.a from tblB) select tblA.a,tblA.b,tblA.c,tblA.d from tblA left outer join tblB on tblA.a = tblB.a where tblB.a is null
哪个会更好?我的假设是,一般而言,联接会更好,除非子选择返回的结果集很小。
解决方案
回答
根据我的观察,MSSQL服务器为这些查询生成相同的查询计划。
回答
我创建了一个与MSSQL2005上的问题类似的简单查询,并且说明计划有所不同。第一个查询似乎更快。我不是SQL专家,但是估计的解释计划对查询1有37%的查询,对查询2有63%的查询。看来,查询2的最大开销是联接。这两个查询都有两次表扫描。
回答
RDBMS会"重写"查询以优化查询,因此这取决于我们使用的系统,我想它们最终将在大多数"良好"数据库上提供相同的性能。
我建议选择一个更清晰,更易于维护的设备,以我的钱,这是第一个。调试子查询要容易得多,因为它可以独立运行以检查是否正常。
回答
我同意汤姆的回答,我们应该选择一个更容易理解和维护的答案。
无法预测任何数据库中任何查询的查询计划,因为我们没有给我们索引或者数据分配。预测更快的唯一方法是对数据库运行它们。
根据经验,当我不需要在select子句中包含tblB中的任何列时,我倾向于使用子选择。当我想使用" in"谓词(通常用于问题中包含的" not in")时,我肯定会进行子选择,其简单原因是当我们或者某人更容易理解这些谓词时否则又回来改变他们。
回答
在SQL Server中,第一个查询会更快,我认为这有点反常。子查询似乎应该更慢。在某些情况下(随着数据量的增加),"存在"可能比"输入"更快。
回答
不相关的子查询也可以。我们应该使用描述所需数据的内容。如前所述,这很可能被重写为相同的计划,但不能保证!此外,如果表A和B不是1:1,那么我们将从联接查询中获得重复的元组(因为IN子句执行隐式DISTINCT排序),因此始终最好编写所需的代码并实际考虑结果。
回答
应当注意,如果TblB.a不是唯一的,这些查询将产生不同的结果。
回答
好吧,这取决于数据集。根据我的经验,如果数据集较小,则选择NOT IN,如果数据集较大,则选择LEFT JOIN。在大型数据集上,NOT IN子句似乎非常慢。
我可能要补充的另一件事是,解释计划可能会产生误导。我看过几个查询,其中解释太高了,查询在1秒以下运行。另一方面,我看到了具有出色解释计划的查询,并且这些查询可能会运行数小时。
因此,总而言之,会对数据进行测试并亲自查看。