【问题标题】:Joins, conditions and speed in SQLSQL 中的连接、条件和速度
【发布时间】:2016-10-18 11:08:34
【问题描述】:

在准备一些请求时,我正在写这个:

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 特有的)

【问题讨论】:

  • 它们是一样的吗?尝试一下。哪个更快?尝试一下。使用本地测试服务器。你没有?设置它。
  • 我记得在Oracle 上问过自己同样的问题,当我检查解释计划时,它是相似的。您可以为您的数据库尝试相同的操作。
  • 您的问题特定于 Vertica,因为它取决于查询的优化方式。解决这种性能的通常方法是索引、分区和算法的选择。通常,我们依靠优化器来做出合理的决定。

标签: sql vertica


【解决方案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. 在有意义的地方下推谓词

也就是说,这两个语句之间应该没有区别。很可能它正在下推第一个谓词以使其更像第二个谓词。如果您收集了统计信息,优化器应该足够聪明,可以以相同的方式(或非常接近)查询这些信息。

这并不是说我没有看到您在 Vertica 中为我“修复”查询问题的第二个查询中的内容...但通常只有当我使用多个 COUNT(DISTINCT ...) 表达式或 theta 连接时,等等。

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

当然,我会提到你真的只需要解释一下这两种方法。只需确保收集到统计信息即可。

希望对您有所帮助。

【讨论】:

    【解决方案2】:

    您的第一个查询可以正常工作,但第二个查询将不会执行并导致错误。背后的原因是,你正在服用JOIN (SELECT * FROM tb WHERE B.col3 = 'whatever') 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 子句中,您可以提供 ' * ' 运算符,它为您提供所有三个表中的所有列。但是您不应该在连接的子查询中使用运算符,因为连接是以这种方式编码的。

    这两个查询没有太大区别,但与第二个相比,您的第一个逻辑执行得更快。在第二个逻辑中,使用了两个子查询,在数据库中进行多次搜索,并为您提供比第一个逻辑慢一点的结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-30
      • 2013-05-18
      • 2014-12-25
      • 2011-03-29
      相关资源
      最近更新 更多