生成笛卡尔积的两个表之间的连接

Posted

技术标签:

【中文标题】生成笛卡尔积的两个表之间的连接【英文标题】:Joins between two tables generating Cartesian product 【发布时间】:2013-11-16 20:29:55 【问题描述】:

我正在阅读一本书“在 Microsoft SQL Server 2008 内部:T-SQL 查询*,它通过一个示例说明,当在两个表之间进行任何连接时,首先在它们之间发生笛卡尔积,然后使用 ON 条件对其进行过滤然后按“RIGHT”、“LEFT”或“FULL”连接类型。

从那本书的一个例子,

SELECT C.customerid, COUNT(O.orderid) AS numorders
FROM dbo.Customers AS C
LEFT OUTER JOIN dbo.Orders AS O
ON C.customerid = O.customerid

Customer 表有 4 行,Orders 有 7 行。因此,第一个笛卡尔积将生成 4*7 = 28 行,然后将通过“ON”子句和 LEFT OUTER 进行过滤。

这是否意味着无论我使用哪种连接类型,每次笛卡尔积都会在表之间发生?那么为什么我们会看到不同连接之间的性能差异呢?

【问题讨论】:

对不起我的英语不好..可能是因为我无法清楚地理解那本书的内容 试试CROSS JOIN声明 @Aycan 我没听懂你。我的问题的目的是了解内部 t-sql 的工作原理。 @AycanYaşıt 我相信 OP 想知道左连接是否实际上可以被视为后来过滤的交叉连接,或者它是 SQL Server 内部实际发生的情况。 抱歉,我当时没收到问题。 【参考方案1】:

SQL Server 当然不会为每个连接计算笛卡尔积然后对其进行过滤,它所做的是将您的 SQL 语句与左、右、内......将根据表上的统计信息来决定要使用的物理连接运算符。

有3种物理运算符:

嵌套循环加入 合并加入 哈希连接

所有 3 个都有自己的理想场景,它们最适合使用(我不打算在这里解释它们,每个都有大量文章),这主要取决于所涉及的每个表的基数估计连接和优化器期望返回多少行的统计信息,以了解使用了哪一个。

克雷格·弗里德曼 (Craig Freedman) 有一系列很棒的博客文章,讨论了 SQL Server 中的连接是如何工作的,都在这里:

Joins - Craig Freedman

我建议查看该列表中的最后 5 篇文章,其中包括对连接的介绍、连接属性的摘要以及每个物理连接运算符的合理深入信息。

【讨论】:

+1 我可以看到比我预期的更详细的信息 很棒的帖子和精彩的回答——正是我所需要的。【参考方案2】:

两个表之间的任何连接首先发生在它们之间的笛卡尔积,然后使用 ON 条件过滤,然后通过“RIGHT”、“LEFT”或“FULL”连接类型进行过滤。

只是对所做工作的逻辑描述。结果将与此相同,但会根据您拥有的索引和表中的数据以不同的方式实现。

查看set showplan on,然后进行查询,它将解释如何查找数据。希望这本书能在你深入研究时解释这一点。

【讨论】:

我做到了。通过阅读它,我假设它是表格格式的执行计划。如果我错了,请纠正我。 我认为这是正确的,但是我认为你要做的主要是在书中多学习,当你了解更多时再看这个问题 这确实是正确的选择:)。但是,我会继续打开这个选项,看看我们是否能得到更多的回应。在任何情况下,我都会在编写本书的过程中分享我的发现。【参考方案3】:

说笛卡尔积发生然后被过滤是非常误导的。如果是这种情况,那么连接 200 万行表几乎是不可能的,因为首先,您将从一万亿行结果集开始,然后对其进行过滤。没有多少 SQL-Server 实现可以处理那个。

所以,不,对于编写良好的查询,笛卡尔积不是该过程的第一步。对于一个写得不好的查询,所有的赌注都被取消了。可以强制 SQL-Server 做出该选择,但这几乎毫无疑问是程序员错误的一个简单示例。

【讨论】:

以上是关于生成笛卡尔积的两个表之间的连接的主要内容,如果未能解决你的问题,请参考以下文章

sql join 的语句怎么写?

多表查询

多表联查--00---概述---SQL92,99语法

SQL多表查询

基于笛卡尔坐标点积的算法计算地理距离

mysql连接查询和子查询