使用多个 WHERE 有效地连接两个表

Posted

技术标签:

【中文标题】使用多个 WHERE 有效地连接两个表【英文标题】:Efficiently Join Two Tables with Several WHEREs 【发布时间】:2020-06-01 04:34:32 【问题描述】:

当我尝试加入两个大表并使用WHERE...OR 子句选择条目时遇到问题:

SELECT A.a, B.b 
FROM A JOIN B 
ON A.equal = B.equal 
WHERE A.condition1 > 100 OR B.condition2 > 200

这里A和B是非常非常大的表,条目需要匹配不同表中的WHERE...OR条件。请问有什么方法可以优化这个子句吗?

提前谢谢。

【问题讨论】:

单独的 WHERE 条件选择性是否高(每个单独的表)?如果为真,则尝试在子查询中应用条件。 您可能会觉得这很有帮助:***.com/questions/13750475/… 或见meta.***.com/questions/333952/… @SGM 。 . .我猜你正在使用 Hive,所以我删除了 mysql 标签(答案实际上并不重要,除了索引)。您应该适当地标记数据库。 【参考方案1】:

OR 条件通常是性能杀手。

如果您的查询运行缓慢,您可以尝试的另一种方法是union 两个子查询,例如:

SELECT A.a, B.b 
FROM A JOIN B ON A.equal = B.equal 
WHERE A.condition1 > 100
UNION
SELECT A.a, B.b 
FROM A JOIN B ON A.equal = B.equal 
WHERE B.condition2 > 100

您希望在 A(condition1, equal)B(condition2, equal) 上建立索引以提高性能。

如果你能保证子查询的结果集之间没有重叠(即不存在两个条件同时为真的行),那么你可以把UNION改为UNIN ALL:差远了效率更高,因为数据库不需要在结果集中查找重复项。

【讨论】:

【参考方案2】:

这是 GMB 答案的变体。但是因为你关心性能,所以值得强调。您想使用带有适当索引的UNION ALL

SELECT A.a, B.b 
FROM A JOIN B ON A.equal = B.equal 
WHERE A.condition1 > 100
UNION ALL
SELECT A.a, B.b 
FROM A JOIN B ON A.equal = B.equal 
WHERE B.condition2 > 100 AND A.condition1 <= 100;

UNION ALL 的使用删除了删除重复项的步骤。

以上假设A.condition1 永远不是NULL。这很容易处理,但只会使查询复杂一点。

在 Hive 中,只有当其中一个或两个条件非常有选择性时,这才会真正提高性能——通过减少JOIN 中匹配的行数。如果每个都选择了 90% 的行,那么您的版本可能非常相似。

如果您的数据库可以使用索引,那么您希望:

A(condition1, equal, a) B(equal, b) B(condition2, equal, b) A(equal, a, condition1)

【讨论】:

【参考方案3】:

研究执行日志。如果是歪斜(单个减速器运行缓慢),请参阅this answer。如果没有偏斜,那么

尝试增加并行度:

Tez 上 Mappers 的示例设置:

set hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat;
set tez.grouping.max-size=32000000;
set tez.grouping.min-size=32000;

如果您决定在 MR 而不是 Tez 上运行 Mappers 的示例设置:

set mapreduce.input.fileinputformat.split.minsize=32000; 
set mapreduce.input.fileinputformat.split.maxsize=32000000; 

--reducers 的示例设置:

set hive.exec.reducers.bytes.per.reducer=32000000; --decrease this to increase the number of reducers, increase to reduce parallelism

使用这些设置。成功标准是更多的 mapper/reducer,并且你的 map 和 reduce 阶段运行得更快。

另见:https://***.com/a/48487306/2700344

如果 WHERE 条件是选择性的并且较小的过滤数据集适合内存(连接之前)并且启用了映射连接,@GordonLinoff 配方将正常工作:set hive.auto.convert.join=true;

【讨论】:

以上是关于使用多个 WHERE 有效地连接两个表的主要内容,如果未能解决你的问题,请参考以下文章

lambda 表达式使用 select 和 where 子句连接多个表

oracle数据库的连接

SQL server 使用 内联结(INNER JOIN) 联结多个表 (以及过滤条件 WHERE, AND使用区别)

有效地从子查询中选择多个列(放置在 SELECT 线索中)

使用 MS Access 如何使用多个连接和 where 子句执行更新?

Oracle:有效地使用where子句过滤时间戳列以获取特定日期的所有记录