当我开始编写数据库查询时,我还不知道JOIN关键字,当然我只是扩展了我已经知道的内容并编写了这样的查询:

SELECT a.someRow, b.someRow 
FROM tableA AS a, tableB AS b 
WHERE a.ID=b.ID AND b.ID= $someVar

现在我知道这和INNER JOIN一样,我在代码中找到所有这些查询并问自己是否应该重写它们。他们有什么臭的或他们就好吗?


编辑:

我的回答摘要:此查询没有任何问题但是使用关键字最有可能使代码更具可读性/可维护性。

我的结论:我不会改变旧的查询,但我会纠正我的写作风格,并在将来使用关键字。

感谢您的回答!

有帮助吗?

解决方案

在某些常见情况下,仅使用 WHERE 过滤联接可能效率极低。例如:

SELECT * FROM people p, companies c 
    WHERE p.companyID = c.id AND p.firstName = 'Daniel'

大多数数据库都会完全按字面意思执行此查询,首先使用笛卡尔积 >人和公司表和然后过滤那些具有匹配 companyID id 字段的人。虽然完全不受约束的产品不存在于存储器中的任何地方,但仅存在一段时间,但其计算确实需要一些时间。

更好的方法是使用相关的 JOIN 对约束进行分组。这不仅在主观上更容易阅读,而且效率更高。正是如此:

SELECT * FROM people p JOIN companies c ON p.companyID = c.id
    WHERE p.firstName = 'Daniel'

它有点长,但是数据库能够查看 ON 子句并使用它来直接计算完全约束的 JOIN ,而不是从< em>所有然后限制下来。这样计算速度更快(特别是对于大型数据集和/或多表连接)并且需要更少的内存。

我更改了我看到的每个使用“逗号 JOIN ”的查询。句法。在我看来,它存在的唯一目的是简洁。考虑到性能影响,我认为这不是一个令人信服的理由。

其他提示

更详细的 INNER JOIN,LEFT OUTER JOIN,RIGHT OUTER JOIN,FULL OUTER JOIN 来自ANSI SQL / 92语法,用于加入。对我来说,这种详细程度使得开发人员/ DBA更清楚地了解了连接的意图。

在SQL Server中总是有要检查的查询计划,文本输出可以按如下方式进行:

SET SHOWPLAN_ALL ON
GO

DECLARE @TABLE_A TABLE
(
    ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    Data VARCHAR(10) NOT NULL
)
INSERT INTO @TABLE_A
SELECT 'ABC' UNION 
SELECT 'DEF' UNION
SELECT 'GHI' UNION
SELECT 'JKL' 

DECLARE @TABLE_B TABLE
(
    ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    Data VARCHAR(10) NOT NULL
)
INSERT INTO @TABLE_B
SELECT 'ABC' UNION 
SELECT 'DEF' UNION
SELECT 'GHI' UNION
SELECT 'JKL' 

SELECT A.Data, B.Data
FROM
    @TABLE_A AS A, @TABLE_B AS B
WHERE
    A.ID = B.ID

SELECT A.Data, B.Data
FROM
    @TABLE_A AS A
    INNER JOIN @TABLE_B AS B ON A.ID = B.ID

现在我将省略表变量创建的计划,但两个查询的计划是相同的:

 SELECT A.Data, B.Data  FROM   @TABLE_A AS A, @TABLE_B AS B  WHERE   A.ID = B.ID
  |--Nested Loops(Inner Join, OUTER REFERENCES:([A].[ID]))
       |--Clustered Index Scan(OBJECT:(@TABLE_A AS [A]))
       |--Clustered Index Seek(OBJECT:(@TABLE_B AS [B]), SEEK:([B].[ID]=@TABLE_A.[ID] as [A].[ID]) ORDERED FORWARD)
 SELECT A.Data, B.Data  FROM   @TABLE_A AS A   INNER JOIN @TABLE_B AS B ON A.ID = B.ID
  |--Nested Loops(Inner Join, OUTER REFERENCES:([A].[ID]))
       |--Clustered Index Scan(OBJECT:(@TABLE_A AS [A]))
       |--Clustered Index Seek(OBJECT:(@TABLE_B AS [B]), SEEK:([B].[ID]=@TABLE_A.[ID] as [A].[ID]) ORDERED FORWARD)

所以,简短的回答 - 不需要重写,除非你每次维护它们都要花很长时间尝试阅读它们吗?

这更像是一种语法选择。我更喜欢将我的连接条件与我的连接分组,因此我使用INNER JOIN语法

SELECT a.someRow, b.someRow
FROM tableA AS a
INNER JOIN tableB AS b
  ON a.ID = b.ID
WHERE b.ID = ?

(?作为占位符)

示例中的语法没有错。 'INNER JOIN'语法通常称为'ANSI'语法,并且在您的示例中说明的样式之后。它的存在是为了澄清连接的类型/方向/组成部分,但通常在功能上与您所拥有的不同。

对'ANSI'连接的支持是每个数据库平台,但它现在或多或少是普遍的。

作为附注,使用'ANSI'语法的一个附加是'FULL OUTER JOIN'或'FULL JOIN'。

希望这有帮助。

一般来说:

使用JOIN关键字链接(即“加入”)主键和外键。

使用WHERE子句将结果集限制为仅您感兴趣的记录。

可能出现的一个问题是,当您尝试混合使用旧的“逗号样式”时,可能会出现问题。在同一查询中连接SQL-92连接,例如,如果您需要一个内连接和另一个外连接。

SELECT *
FROM table1 AS a, table2 AS b
 LEFT OUTER JOIN table3 AS c ON a.column1 = c.column1
WHERE a.column2 = b.column2;

问题是最近的SQL标准表示在逗号连接之前评估JOIN。所以对“a”的引用在ON子句中给出错误,因为尚未定义相关名称,因为正在评估ON子句。这是一个非常令人困惑的错误。

解决方案是不混合两种类型的连接。您可以继续在旧代码中使用逗号样式,但如果您编写新查询,请将所有联接转换为SQL-92样式。

SELECT *
FROM table1 AS a
 INNER JOIN table2 AS b ON a.column2 = b.column2
 LEFT OUTER JOIN table3 AS c ON a.column1 = c.column1;

在旧的连接语法中要考虑的另一件事是,由于没有on子句,因此很容易意外地获得cartesion连接。如果Distinct关键字在查询中并且它使用旧样式连接,请将其转换为ANSI标准连接,并查看是否仍需要distinct。如果您以这种方式修复意外的caresion连接,则可以通过重写来指定连接和连接字段,从而极大地提高性能。

我避免隐式连接;当查询非常大时,它们会使代码难以解密

通过显式连接和良好的格式化,代码更易读,更易理解,无需注释。

这还取决于你是以这种方式进行内部连接还是外部连接。例如,WHERE子句(= *和* =)中外部联接的MS SQL Server语法可以提供与OUTER JOIN语法不同的结果,并且不再受支持( http://msdn.microsoft.com/en-us/library/ms178653(SQL.90).aspx )。

scroll top