我对优化查询的运行时间很感兴趣:
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子句放置在子查询中,而不是在联合的末尾,但这使我想知道首先联合/联合然后进行单个内部联接是否更快?
我们非常感谢您的帮助(即使这意味着这是最有效的查询结构)。
答案 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_A
和source_B
之间的关系性质,基数和可用索引。
您可以根据source_B
中存在的先决条件进行过滤,或者增加行,或者检索其他列(您已经提到过)。但是后者并不能说明所有问题。有解释的余地...
答案 1 :(得分:1)
要提高性能,一个关键方面是尽快删除未选择的行。拥有两个单独的联接是一个不错的选择,因为您将强制联接立即排除不匹配的行。
但是首先,您需要确保引擎使用最快的访问谓词从大型表source_A
和source_C
中过滤数据。对于您的过滤谓词,您正在使用简单的等式……这是完美的。我会在您的表中添加以下索引(如果您还没有的话):
create index ix1 on source_A (field1, field2);
create index ix2 on source_C (field1, field2);
现在,一旦选择了source_A
和source_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)
source_A
表的排序键为(x,y)
,所有表的分发键为common_field1
。无论查询的编写方式如何,这都会极大地影响您的查询速度。UNION ALL
可以提供很好的提升。-
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
)