Sql 子查询与传统的WHERE子句连接?
当连接到表的子集时,有什么理由选择其中一种格式而不是另一种格式 子查询版本:Sql 子查询与传统的WHERE子句连接?,sql,sql-server,Sql,Sql Server,当连接到表的子集时,有什么理由选择其中一种格式而不是另一种格式 子查询版本: SELECT ... FROM Customers AS c INNER JOIN (SELECT * FROM Classification WHERE CustomerType = 'Standard') AS cf ON c.TypeCode = cf.Code INNER JOIN SalesReps s ON cf.SalesRepID = s.SalesRepID vs结尾的WHERE子句: SE
SELECT ...
FROM Customers AS c
INNER JOIN (SELECT * FROM Classification WHERE CustomerType = 'Standard') AS cf
ON c.TypeCode = cf.Code
INNER JOIN SalesReps s ON cf.SalesRepID = s.SalesRepID
vs结尾的WHERE子句:
SELECT ...
FROM Customers AS c
INNER JOIN Classification AS cf ON c.TypeCode = cf.Code
INNER JOIN SalesReps AS s ON cf.SalesRepID = s.SalesRepID
WHERE cf.CustomerType = 'Standard'
结尾的WHERE子句感觉更为“传统”,但第一个可以说更为明确,尤其是在连接变得越来越复杂的情况下
我能想到的选择第二个的另一个原因是,第一个上的“SELECT*”可能会返回以后不用的列(在这种情况下,我可能只需要返回cf.Code和cf.SalesRepID)第二个子句肯定更清楚,我怀疑优化器也会更喜欢它。理想情况下,您应该指定所需的列。我总是喜欢第二个变量,因为如果使用第一个变量,查询将变得非常复杂
性能可能有负面影响。我想说的是,在同等的联接/子查询情况下,优化器将生成类似的执行计划,您使用的路径应该由在查询中提供最清晰意图的内容决定。(例如,根据可维护性进行选择)我总是选择第二种,直到我被迫使用另一种
在FROM中保留连接,在WHERE中保留条件。第三个选项如何
SELECT ...
FROM Customers AS c
INNER JOIN Classification AS cf
ON cf.CustomerType = 'Standard'
AND c.TypeCode = cf.Code
INNER JOIN SalesReps AS s
ON cf.SalesRepID = s.SalesRepID
就我个人而言,我更喜欢使用JOIN
语法来指示定义了整个集合的语句、外键或其他指示两行应合并以在结果集中形成一行的条件
WHERE
子句包含筛选我的结果集的条件。可以说,当您执行大量联接时,这可能会变得非常臃肿和复杂,但是当您在集合中思考时,它遵循一种逻辑:
选择我想要的列
表以定义我要从中获取行的集合JOIN
- 筛选出不符合我的条件的行
SET SHOWPLN_ALL ON
然后是每个查询
我认为第一个可能在简单查询中运行相同的计划,但第二个总是运行相同或更好的计划,特别是在更复杂的查询中。我只在需要不同的查询时使用子查询,例如group by或过于复杂的查询 我还将对第二个查询执行一个变体,如下所示:
SELECT ...
FROM Customers AS c
INNER JOIN Classification AS cf
ON c.TypeCode = cf.Code
AND cf.CustomerType = 'Standard'
INNER JOIN SalesReps AS s
ON cf.SalesRepID = s.SalesRepID
这将在查询的连接部分删除“多余的行”。对于这个查询,可能不会对优化器产生影响,但在其他查询(外部联接、进一步的子查询等)中肯定会产生影响。正如其他人所说,第二个是更好的选择。但是,如果您移动到外部连接,则还要考虑过滤器位置的含义。如果您可能想要查看所有客户,并且对于那些被分类为“标准”的客户,您想要销售代表信息,那么请查看下面的SQL
SELECT ...
FROM Customers AS c
LEFT JOIN Classification AS cf
ON c.TypeCode = cf.Code
AND cf.CustomerType = 'Standard'
LEFT JOIN SalesReps s
ON cf.SalesRepID = s.SalesRepID
下面的代码不会产生与上面相同的结果。它将有更少的行并且是不正确的
SELECT ...
FROM Customers AS c
LEFT JOIN Classification AS cf
ON c.TypeCode = cf.Code
LEFT JOIN SalesReps s
ON cf.SalesRepID = s.SalesRepID
WHERE cf.CustomerType = 'Standard'
但特别是对于你的问题,我希望看到以下版本。我相信这个版本的意图是明确的
SELECT ...
FROM Customers AS c
JOIN Classification AS cf
ON c.TypeCode = cf.Code
AND cf.CustomerType = 'Standard'
JOIN SalesReps s
ON cf.SalesRepID = s.SalesRepID
第一个版本是派生表。不要将其与子查询混淆 我会检查各种版本的性能(并确保它们都提供相同的结果,您会惊讶地发现人们在优化代码时经常忘记相同的结果是重要的!)。我怀疑编写第一个版本是为了模拟连接到的记录的数量,以提高性能(派生表通常比其他结构提高性能,并且它可能已经取代了相关子查询,而它几乎肯定会比其他结构具有更好的性能)。不管它有没有,我都必须在你的数据库中运行才能看到 基本上,当两个结构具有相同的结果时,我倾向于选择执行速度更快的结构。是的,这可能有点难以理解(您可以随时添加注释,解释您做了什么以及为什么要帮助维护人员)。但性能是所有数据库访问中必须考虑的三个关键因素之一(安全性和数据完整性是另外两个)。在数据库中,特别是对于频繁运行的查询,性能应该优于维护的方便性。当您需要查看某个内容时(大多数查询的访问时间都少于10分钟),避免一年多花10分钟来理解该内容对于每个用户来说都是不值得的,尤其是当它每天运行数千次时
SELECT ...
FROM Customers AS c
INNER JOIN (SELECT * FROM Classification WHERE CustomerType = 'Standard') AS cf
ON c.TypeCode = cf.Code
INNER JOIN SalesReps s ON cf.SalesRepID = s.SalesRepID
SELECT ...
FROM Customers AS c
INNER JOIN Classification AS cf ON c.TypeCode = cf.Code
INNER JOIN SalesReps AS s ON cf.SalesRepID = s.SalesRepID
WHERE cf.CustomerType = 'Standard'
SQL Server
将对两个查询进行相同的处理
这些查询在性能方面是相同的。您可以在上自由交换,WHERE
和内联视图条件:SQL Server
的优化器足够智能,可以找出最佳方案。
当需要时,第一个查询更容易转换为外部联接
,但是,在这种情况下,它的措辞可能更好,如下所示:
SELECT ...
FROM Customers AS c
INNER JOIN -- or OUTER JOIN
Classification AS cf
ON cf.Code = c.TypeCode
AND cf.CustomerType = 'Standard'
INNER JOIN -- or OUTER JOIN
SalesReps AS s
ON s.SalesRepID = cf.SalesRepID
在编写查询时,我尝试编写它们,以便从查询中清楚地看到关键性质
如果cf.code
上有一个单列键,我会使用这个:
SELECT ...
FROM Customers AS c
INNER JOIN
Classification AS cf
ON cf.Code = c.TypeCode
INNER JOIN
SalesReps AS s
ON s.SalesRepID = cf.SalesRepID
WHERE cf.CustomerType = 'Standard'
如果键是cf(code,CustomerType)
,则此键:
SELECT ...
FROM Customers AS c
INNER JOIN
Classification AS cf
ON cf.Code = c.TypeCode
AND cf.CustomerType = 'Standard'
INNER JOIN
SalesReps AS s
ON s.SalesRepID = cf.SalesRepID
SELECT ...
FROM Customers AS c
INNER JOIN
(
SELECT *
FROM Classification
WHERE CustomerType = 'Standard'
) AS cf
ON cf.Code = c.TypeCode
INNER JOIN
SalesReps s
ON s.SalesRepId = cf.SalesRepID
,如果键是cf(CustomerType,code)
,则此键:
SELECT ...
FROM Customers AS c
INNER JOIN
Classification AS cf
ON cf.Code = c.TypeCode
AND cf.CustomerType = 'Standard'
INNER JOIN
SalesReps AS s
ON s.SalesRepID = cf.SalesRepID
SELECT ...
FROM Customers AS c
INNER JOIN
(
SELECT *
FROM Classification
WHERE CustomerType = 'Standard'
) AS cf
ON cf.Code = c.TypeCode
INNER JOIN
SalesReps s
ON s.SalesRepId = cf.SalesRepID
还有一点需要注意的是:在MySQL
中,内联视图的效率远远低于连接,因此我不会在MySQL
中使用它们
但是,SQL Server的情况并非如此。我在Oracle DBMS上运行了4种变体,它们在运行时或多或少都是等效的。我没有使用复杂的子查询,只是从表中选择一列(使用子查询方法时),并以各种方式筛选该表(即直接在子选择/派生表中或在main where cl中)