在SQL或MySQL中不使用JOIN关键字的连接是否有问题?
题
当我开始编写数据库查询时,我还不知道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 )。