SQL中的连接,条件和速度

时间:2016-10-18 11:08:34

标签: sql vertica

在准备一些请求时,我写的是:

SELECT *
FROM ta A
JOIN tb B
    ON A.col1 = B.col1 
JOIN tc C
    ON B.col2 = C.col2 
WHERE B.col3 = 'whatever'
AND C.col4 = 'whatever2'

我开始考虑以下事项:

SELECT *
FROM ta A
JOIN (SELECT * FROM tb WHERE col3 = 'whatever') B
    ON A.col1 = B.col1
JOIN (SELECT * FROM tc WHERE col4 = 'whatever2') C
    ON B.col2 = C.col2

(如果我没弄错的话,结果会是一样的)。我想知道它是否会明显更快?我的猜测是它会,但我有兴趣知道为什么/为什么不呢?

(因为我们的服务器目前处于停机状态,我现在无法自己测试,所以我在这里问,我希望你不介意。)

(如果重要的话,引擎是Vertica,但我的问题并不是特定于Vertica)

2 个答案:

答案 0 :(得分:1)

你的第二个问题有点过了,应该是:

SELECT *
FROM ta A
JOIN (SELECT * FROM tb WHERE tb.col3 = 'whatever') B
    ON A.col1 = B.col1
JOIN (SELECT * FROM tc WHERE tc.col4 = 'whatever2') C
    ON B.col2 = C.col2

注意内联视图where子句需要引用范围中的表,而不是视图的别名。 B和C超出了内联视图的范围。

在任何情况下,因为您正在进行内部联接,所以从结果角度来看无关紧要,因为条件是相同的,无论它是在联接前还是在联接后发生。

您可以合理地依赖优化器来执行以下操作:

  1. 仅在需要时实现所需的列。
  2. 将谓词推到有意义的地方
  3. 尽管如此,这两个陈述之间应该没有区别。最有可能是它推迟了第一个的谓词,使其更像第二个。如果您收集了统计信息,那么优化器应该足够智能,以相同的方式(或非常接近)查询这些。

    这并不是说我在第二次查询中没有看到你在Vertica中为我修复查询问题...但通常只有当我使用多个COUNT(DISTINCT ...)表达式或theta时加入等等。

    现在如果这是一个外连接,那么语句会有所不同。第一个将在连接后应用过滤器,第二个将在连接之前应用过滤器。

    当然,我会提到你真的需要解释这两种方法。只需确保收集统计数据。

    希望它有所帮助。

答案 1 :(得分:0)

嗨,很好的尝试。非常感谢。您的第一个查询将正常工作,但第二个查询将不会执行并导致错误。背后的原因是,你正在采取加入(SELECT * FROM tb WHERE B.col3 ='无论')B ON A.col1 = B.col1 。在这种情况下,您将该列与 A.col1 = B.col1 进行匹配。在这里,你将从 ta 表中获得A.col1,但你不会得到 B.col1 。在联接中指定子查询时,不应使用' *' 运营商。联接将不会在子查询中识别此运算符。您需要指定所需的列名称。像下面查询中的示例一样,

SELECT *
FROM ta A
JOIN (SELECT col1,col2 FROM tb WHERE B.col3 = 'whatever') B
    ON A.col1 = B.col1
JOIN (SELECT col2 FROM tc WHERE C.col4 = 'whatever2') C
    ON B.col2 = C.col2

这将执行并为您提供结果。在第一个连接子查询 col1,col2 中使用了两列,因为您在第二个连接条件中使用来自B表的条件 B.col2 。在select子句中,您可以提供' *' 运算符,它为您提供所有三个表中的所有列。但是你不应该在连接的子查询中使用运算符,因为连接以这样的方式编码 两个查询没有太大区别,但与第二个逻辑相比,您的第一个逻辑执行速度更快。在第二个逻辑中,使用了两个子查询,它们在数据库中进行多次搜索,并为您提供比第一个逻辑慢得多的结果 希望你得到你所要求的,如果仍然有任何并发​​症随时提出任何问题