【问题标题】:Partition a very large INNER JOIN SQL query对非常大的 INNER JOIN SQL 查询进行分区
【发布时间】:2026-02-19 23:20:03
【问题描述】:

sql 查询是相当标准的内连接类型。 例如,比较 n 个表以查看所有 n 个表中存在哪些 customerId,这将是一个基本的 WHERE ... AND 类型查询。

问题是表的大小 > 1000 万条记录。数据库是非规范化的。规范化不是一种选择。 查询要么需要很长时间才能完成,要么永远不会完成。

我不确定它是否相关,但我们正在将 spring xd 作业模块用于其他类型的查询。

我不确定如何对此类作业进行分区,以便它可以并行运行,从而减少时间,因此如果步骤/子部分失败,它可以从中断的地方继续。

其他有类似问题的帖子建议使用除数据库引擎之外的替代方法,例如在代码中实现 LOOP JOIN 或使用 MapReduce 或 Hadoop,我不确定它们是否值得研究这个用例。

p>

这种操作的标准方法是什么,我希望它相当普遍。我可能使用了错误的搜索词来研究方法,因为我没有遇到任何标准解决方案或明确的方向。

相当神秘的原始要求是:

比较三个非常大的表中的party_id 列,以识别三个表中可用的客户 即如果它是三个之间的 AND 操作。 SAMPLE1.PARTY_ID 和 SAMPLE2.PARTY_ID 和 SAMPLE3.PARTY_ID

如果运算为 OR,则选择三个表中的所有可用客户。 SAMPLE1.PARTY_ID 或 SAMPLE2.PARTY_ID 或 SAMPLE3.PARTY_ID

在表格之间使用AND / OR,然后根据需要执行比较。 SAMPLE1.PARTY_ID 和 SAMPLE2.PARTY_ID 或 SAMPLE3.PARTY_ID

我用这个定义设置了大约 4 个测试表

CREATE TABLE `TABLE1` (
  `CREATED` datetime DEFAULT NULL,
  `PARTY_ID` varchar(45) NOT NULL,
  `GROUP_ID` varchar(45) NOT NULL,
  `SEQUENCE_ID` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`SEQUENCE_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=978536 DEFAULT CHARSET=latin1;

然后将 1,000,000 条记录添加到应该导致连接的范围内的每个随机数。

我使用了以下测试查询

SELECT `TABLE1`.`PARTY_ID` AS `pi1`, `TABLE2`.`PARTY_ID` AS `pi2`, `TABLE3`.`PARTY_ID` AS `pi3`, `TABLE4`.`PARTY_ID` AS `pi4` FROM `devt1`.`TABLE2` AS `TABLE2`, `devt1`.`TABLE1` AS `TABLE1`, `devt1`.`TABLE3` AS `TABLE3`, `devt1`.`TABLE4` AS `TABLE4` WHERE `TABLE2`.`PARTY_ID` = `TABLE1`.`PARTY_ID` AND `TABLE3`.`PARTY_ID` = `TABLE2`.`PARTY_ID` AND `TABLE4`.`PARTY_ID` = `TABLE3`.`PARTY_ID`

它应该在 10 分钟内完成,并且桌子尺寸要大 10 倍。 我的测试查询还没有完成,它已经运行了 15 分钟

【问题讨论】:

  • “比较 n 个表以查看所有 n 个表中存在哪些 customerId”对我来说听起来不像是“相当标准的内部连接类型”。如果您发布了一个关于您正在尝试做什么的示例查询,这可能会有所帮助。
  • 进行自己的分区当然很麻烦。如果您足够频繁地达到这种处理水平,您是否愿意迁移到大数据环境?如果是这样,我建议trustedanalytics.github.io - 我知道它可以处理你想要做的加入级别。
  • @Uueerdo 我添加了需求的描述。这是我最初的猜测,这将是一个内部连接。但显然使用 sql 并不是最好的解决方案,因为它需要的时间太长。我在想数据科学或其他方面可能有一些替代算法
  • “太长”有多长?您现有的查询运行多长时间?您希望它运行多长时间?你要加入多少张桌子?他们在上面设置了哪些索引?您希望返回大约(数量级)多少行?是所有表都 > 1000 万条记录,还是有些明显更小?单个客户是否会在任何/部分/所有这些表上拥有许多记录? SQL 查询优化通常取决于要优化的查询的具体细节。
  • DBMS 是 MySQL。我没有查询。 AND/OR 组合有许多可能的查询。但总是匹配单个列。这需要不到 10 分钟。目标是编写一个 spring 批处理作业以确保它的故障安全和高效。我也无权访问实际的数据库,否则我会看看示例查询的执行情况。所以我的问题必然是抽象的,而不是我自己的设计。

标签: mysql hadoop join bigdata spring-xd


【解决方案1】:

以下可能比现有的基于连接的查询执行得更好:

select party_id from
(select distinct party_id from SAMPLE1 union all
 select distinct party_id from SAMPLE2 union all
 select distinct party_id from SAMPLE3) as ilv
group by party_id 
having count(*) = 3

修改count(*) 条件以匹配被查询的表数。

如果您想返回 any 表中存在的 party_id 值而不是全部,则省略最后的 having 子句。

【讨论】:

  • 在“任意表”场景中,union allall 部分也可以省略。
  • 如果 UNION 将一个表的行结果与另一个表的行(垂直)结合起来,你能解释一下这个查询如何排除任何在 SAMPLE2 中不存在的 party_id 吗?
  • @justify:这就是having count(*) = 3 子句的作用——不在所有3 个表中的任何party_id 值的计数都将小于3。 (这就是为什么必须修改计数条件以匹配查询中的表总数。)
  • @Mark Ba​​nnister:好的,这确实工作得更快!由于这仅适用于所有 AND 或所有 OR,您能否通过正确使用子查询的示例扩展您的答案,以返回 SAMPLE1 AND SAMPLE2 AND SAMPLE3 OR SAMPLE4 AND SAMPLE5 中的 party_id 列表,然后我可以看到如何编写动态代码任何组合的查询生成
  • 另外结果需要包含 GROUP_ID 可能我应该写一个新问题