使用多个 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 子句连接多个表
SQL server 使用 内联结(INNER JOIN) 联结多个表 (以及过滤条件 WHERE, AND使用区别)