mysql - 使用sql联合子查询的组合来处理AND/OR条件的组合以进行客户过滤

标签 mysql sql database bigdata

这是一项与市场分割分析相关的工作,我认为每天运行几次。

我将解释的查询类型需要在 10 分钟内完成,涉及最多 5 个表,每个表中有 1000 万条记录。

我是一个sql菜鸟。我将其实现为 Spring 批处理作业,并且需要确定要使用的最有效的 SQL 查询技术。因此,我可以为 AND/OR 条件的任意组合编写动态查询生成代码。

目标是根据多个表中的存在情况来选择 partyId、groupId,这些表更新太频繁,索引变得非常有用。这些表本身是相同的,本质上是由某些现有进程创建的容器。使用日期范围条件,以便选择仅考虑自上次作业运行以来的更改。 (假设日期范围条件有助于查询优化)

因此,对于我的测试用例,我有 5 个表,全部具有以下结构

CREATE TABLE `TABLE1` (
  `UPDATED` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `PARTY_ID` varchar(20) NOT NULL,
  `GROUP_ID` varchar(20) NOT NULL,
  `SEQUENCE_ID` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`SEQUENCE_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2225551 DEFAULT CHARSET=latin1;

来自 Partition a very large INNER JOIN SQL query 的回答和评论

我拼凑了 2 个可能的查询,一个用于“所有 AND”类型条件,一个用于“所有 OR”类型条件。

select PARTY_ID from
(select distinct PARTY_ID from TABLE1 WHERE (UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00')  union all
 select distinct PARTY_ID from TABLE2 WHERE (UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00')  union all
 select distinct PARTY_ID from TABLE3 WHERE (UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00')  union all
 select distinct PARTY_ID from TABLE4 WHERE (UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00')  union all
 select distinct PARTY_ID from TABLE5 WHERE (UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00')) as ilv
group by PARTY_ID 
having count(*) = 5;

这适用于返回所有表 1-5 中存在的 partyId 的结果集。用户将以 AND/OR 条件的形式提供条件要求,因此这相当于纯粹的 AND 条件集)

select PARTY_ID from
(select distinct PARTY_ID from TABLE1 WHERE (UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00')  union all
 select distinct PARTY_ID from TABLE2 WHERE (UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00')  union all
 select distinct PARTY_ID from TABLE3 WHERE (UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00')  union all
 select distinct PARTY_ID from TABLE4 WHERE (UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00')  union all
 select distinct PARTY_ID from TABLE5 WHERE (UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00')) as ilv
group by PARTY_ID;

这适用于返回存在表 1-5 中任何一个的 partyId 的结果集。用户将以 AND/OR 条件的形式提供条件要求,因此这相当于纯 OR 条件集)

我需要的是一个示例,说明 AND/OR 条件的组合如何转换为这种类型的查询语法(因为它比标准联接快得多)

例如,正确使用子查询返回 TABLE1 和 TABLE2 和 TABLE3 或 TABLE4 和 TABLE5 中的 party_id 列表,然后我可以看到如何为任何组合编写动态查询生成代码。

我的另一个问题是日期范围实际上有助于提高效率吗? 我还可以有效地使用日期范围来对查询进行分区,以便它可以并行运行吗?

我不确定这一点的原因是我猜测 sql 引擎必须循环遍历每个表的所有行,无论条件是否存在。因此,对查询进行分区可能会导致更多的总循环......这样的推理有意义吗?

最佳答案

如果您只想查询当天的行,那么进行夜间作业是有意义的,该作业在当天的每个表上设置一个新分区(并将前一天的行移动到主分区中)对于每个表)。这样,您每次查询应该只查询数千条记录,而不是数百万条记录。

如果日期/时间范围可能来自任何天,那么在每个表上设置新索引(单独在UPDATED上)会更有意义或 UPDATEDPARTY_ID 的组合。如果您有机会,我建议您尝试针对两组索引尝试更新的查询,并查看它们的比较结果。

实现所需的更复杂功能的一种方法可能是对条件表达式求和 - 例如,如果您希望 TABLE1TABLE2 中包含 PARTY_ID TABLE3 TABLE4TABLE5:

select PARTY_ID from
(select distinct PARTY_ID, 'TABLE1' TABLENAME from TABLE1 
 WHERE UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00'  union all
 select distinct PARTY_ID, 'TABLE2' TABLENAME from TABLE2 
 WHERE UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00'  union all
 select distinct PARTY_ID, 'TABLE3' TABLENAME from TABLE3 
 WHERE UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00'  union all
 select distinct PARTY_ID, 'TABLE4' TABLENAME from TABLE4 
 WHERE UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00'  union all
 select distinct PARTY_ID, 'TABLE5' TABLENAME from TABLE5 
 WHERE UPDATED >= '2015-09-18 14:43:44' AND UPDATED <= '2015-09-18 15:00:00') as ilv
GROUP BY PARTY_ID
HAVING SUM(CASE WHEN TABLENAME IN ('TABLE1','TABLE2','TABLE3') THEN 1 END)=3
    OR SUM(CASE WHEN TABLENAME IN ('TABLE4','TABLE5') THEN 1 END)=2;

请注意,等式表达式(在 HAVING 子句中)中的数字需要与 CASE 表达式中检查的表总数相匹配 - 因此查询需要在检查PARTY_ID是否在前三个表中时检查SUMmed CASE表达式是否等于3,并且需要检查第二个表达式是否等于2 在检查最后两个表时。

关于mysql - 使用sql联合子查询的组合来处理AND/OR条件的组合以进行客户过滤,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32653807/

相关文章:

php - 通过一次查询更新大型数据库

.net - 中等信任度下进程内数据库的选项

mysql - 考虑到数据库规范化,我的数据库关系模型是否正确?

sql - 在 UPDATE 语句中使用 HAVING 子句

sql - Postgres 唯一约束与索引

c - 好的数据库与 C 库?

c# - MySQL 与另外两个表一起创建一个表并使用 C# WinForms 添加记录

mysql - 选择具有复杂 JOIN 的行

MySQL脏读与SQL标准中定义的脏读

sql - 是否可以选择比表包含的行更多的行?