优化联合的内部联接吗?

时间:2019-04-17 18:53:41

标签: sql postgresql amazon-redshift

我对优化查询的运行时间很感兴趣:

create temp table table_base as
(
  SELECT table_a.* FROM source_A a
  INNER JOIN
  source_B b
  USING(common_field1)
  WHERE a.field1 = x AND a.field2 = y
) 
UNION
(
  SELECT a.* FROM source_C a
  INNER JOIN
  source_B b
  USING(common_field1)
  WHERE a.field1 = x AND a.field2 = y
) UNION...

每个子查询中的第一个表(在此示例中为source_A和source_C)具有相同的结构,但数据量最大。内部连接到source_B是必要的,我有兴趣添加一个字段并删除source_B的公共字段中不可用的值。

查询本身当前确实在运行,但是我想知道是否有一种更快的方法。我已经将WHERE子句放置在子查询中,而不是在联合的末尾,但这使我想知道首先联合/联合然后进行单个内部联接是否更快?

我们非常感谢您的帮助(即使这意味着这是最有效的查询结构)。

4 个答案:

答案 0 :(得分:1)

除非您打算删除重复的行,否则使用 UNION ALL 而不是UNION,它将大大提高速度。

通常在过程中尽可能早地应用WHERE子句是最快的-即就像您现在拥有它。还允许在适用的情况下使用索引。如果将WHERE / UNION的结果应用UNION ALL,将无法实现。

您真的是说INNER JOIN source_B b吗?从而可能乘以a中的行?目的可能是(为避免重复):

SELECT *
FROM   source_A a
WHERE  a.field1 = x
AND    a.field2 = y
AND    EXISTS (SELECT 1 FROM source_B b WHERE b.common_field1 = a.common_field1)

..同样适用于source_C ...

最佳查询实际上取决于source_Asource_B之间的关系性质,基数和可用索引。
您可以根据source_B中存在的先决条件进行过滤,或者增加行,或者检索其他列(您已经提到过)。但是后者并不能说明所有问题。有解释的余地​​...

答案 1 :(得分:1)

要提高性能,一个关键方面是尽快删除未选择的行。拥有两个单独的联接是一个不错的选择,因为您将强制联接立即排除不匹配的行。

但是首先,您需要确保引擎使用最快的访问谓词从大型表source_Asource_C中过滤数据。对于您的过滤谓词,您正在使用简单的等式……这是完美的。我会在您的表中添加以下索引(如果您还没有的话):

create index ix1 on source_A (field1, field2);
create index ix2 on source_C (field1, field2);

现在,一旦选择了source_Asource_C中的行,您将需要访问source_B。为了使此任务快速完成,您需要确保还存在以下索引:

create index ix3 on source_B (common_field);

您还提到可以使用source_B中的某些列。为了更快地,您可以尝试在其上添加覆盖索引。例如,如果您使用name中的source_B列,则可以将该索引转换为覆盖索引,如下所示:

create index ix3 on source_B (common_field, name); -- added column "name"

最后,完成这些更改后,您应该获得一个执行计划,以查看SQL优化器的工作。这永远不会伤害您,并且会在选择最佳路径时向您详细介绍。使用EXPLAIN来获取它。

答案 2 :(得分:0)

怎么样呢?

    CREATE TEMP TABLE table_base as
(
  SELECT a.*
  FROM (
    (
      SELECT * FROM source_A WHERE a.field1 = x AND a.field2 = y
    )
    UNION
    (
      SELECT * FROM source_C WHERE a.field1 = x AND a.field2 = y
    )
  ) a
  JOIN source_B b 
  USING(common_field1)
)

这样,您可以在JOIN之前执行WHERE(并减少记录数)。最好将其与添加到用于JOIN的任何列中的索引一起使用,而不是最好的选择

答案 3 :(得分:0)

  1. 这取决于您的排序和分布。对于此查询,理想情况下,source_A表的排序键为(x,y),所有表的分发键为common_field1。无论查询的编写方式如何,这都会极大地影响您的查询速度。
  2. 如上所述,如果您在UNION集中没有需要删除重复项的交集,UNION ALL可以提供很好的提升。
  3. 我还将尝试不使用联合的查询。检查以下内容:

-

SELECT source_A.* 
FROM source_A a
LEFT JOIN source_B b
USING(common_field1)
LEFT JOIN source_C c
USING(common_field1)
WHERE a.field1 = x 
AND a.field2 = y
AND (
    b.id is not null
    or c.id is not null
)