当加入表的一个子集时,有什么理由偏好这些格式之一而不是另一种格式?
子查询版本:
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
结束时的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)
答案 0 :(得分:5)
第三种选择呢?
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
语法来指示定义整个集合的语句,外键或其他条件,指示应该连接两行以在结果集中创建一行。 / p>
WHERE
子句包含筛选结果集的条件。可以说,当你执行大量的连接时,这可能会变得非常繁琐和复杂,但是当你在集合中思考时它遵循一种逻辑:
SELECT
我想要的列。JOIN
表来定义我想从中获取行的集合。WHERE
我的条件不符合。通过这种逻辑,我总是选择第二种语法以保持一致的可读性。
答案 1 :(得分:3)
第二个句子肯定更清楚,我怀疑优化器也会更好。理想情况下,您应该指定所需的列。
答案 2 :(得分:3)
第一个版本是派生表。不要将它与子查询混淆。
我会检查各种版本的性能(并确保它们都提供相同的结果,你会惊讶于人们忘记优化代码时,相同的结果很重要!)。我怀疑第一个版本的编写是为了减少加入的记录数量,以提高性能(派生表通常会提高性能而不是其他结构,它可能已经取代了相关的子查询,它几乎肯定会比)。无论是否,我都必须在您的数据库中运行才能看到。
基本上,当两个结构具有相同的结果时,我的偏好是选择性能更快的结构。是的,它可能有点难以理解(您可以随时添加注释,解释您所做的以及为什么要帮助维护者)。但性能是所有数据库访问必须考虑的三个关键事项之一(安全性和数据完整性是另外两个)。性能应该优先于数据库中的维护,特别是对于经常运行的查询。每个用户每次运行时,每隔一段时间避免额外十分钟来理解某些内容(并且大多数查询都会重新查看),每次运行时都不值得花费额外的时间,特别是当它运行数千次时一天一次。
答案 3 :(得分:2)
运行
SET SHOWPLN_ALL ON
然后是每个查询。
我认为第一个可能在简单查询中运行相同的计划,但第二个将始终运行相同或更好,尤其是在更复杂的查询中。
答案 4 :(得分:2)
我只在需要不同查询时使用子查询 - 例如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
这将在查询的joing部分中删除“额外行”。可能不会对此查询的优化器产生影响,但它肯定会在其他查询中(外连接,其他子查询等等)
答案 5 :(得分:1)
正如其他人所说,第二个是更好的选择。但是,如果移动到外部联接,还要考虑过滤器位置的含义。如果您想要查看所有客户以及那些被归类为“标准”的客户,您需要销售代表信息,请查看下面的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
答案 6 :(得分:1)
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
会同时处理两个查询。
ON
,WHERE
和内联视图条件:SQL Server
的优化程序非常智能,可以找出最佳计划。第一个查询在需要时更容易转换为OUTER JOIN
,但是,在这种情况下,可能会更好地表达:
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
,如果密钥是cf (CustomerType, Code)
,那么这个:
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
并非如此。
答案 7 :(得分:1)
我在Oracle DBMS上运行了4个变体,它们在运行时或多或少都相同。我没有唱一个复杂的子查询,只是从表中选择一个列(当使用子查询方法时)并以各种方式过滤该表(即直接在subselect / derived表或main where子句中或在连接表达式条件中。
答案 8 :(得分:0)
我总是喜欢第二种变体,因为如果你先使用,那么查询会变得非常复杂 表现可能会有负面影响。
答案 9 :(得分:0)
我想说,在等效的连接/子查询情况下,优化器将生成类似的执行计划,并且您使用的路由应该由提供查询中最明确意图的内容驱动。 (例如,根据可维护性选择)
答案 10 :(得分:0)
我会一直跟着第二个,直到我被迫使用替代品。
保持连接在WHERE中的FROM和条件。