使用 sql 联合子查询的组合来处理 AND/OR 条件的组合以进行客户筛选

Use combination of sql union sub-queries to handle combinations of AND/OR conditions for customer filtering

这是一项与市场细分分析相关的工作,运行我一天想几次。

查询类型,我将解释,需要在 10 分钟内完成,最多 5 table 秒,每个 table.

有 1000 万条记录

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

objective 是 select partyId, groupId 基于存在于多个 tables 中,这些 tables 更新过于频繁,无法索引到非常有用。 tables 本身是相同的,本质上是由某些现有进程创建的 bin。使用日期范围条件,以便 select 仅考虑自上次作业 运行 以来的更改。 (假定日期范围条件有助于查询优化)

所以对于我的测试用例,我有 5 个 table 都具有以下结构

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;

来自

上的回答和评论

我拼凑了 2 个可能的查询,一个用于 'all AND' 类型条件,一个用于 'all 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;

这适用于 returning 所有 tables 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;

这适用于 returning 那些存在 tables 1-5 中任何一个的 partyId 的结果集。用户将以 AND/OR 条件的形式提供条件要求,因此这等同于纯 OR 条件集)

我需要的是 AND/OR 条件的组合如何转化为此类查询语法的示例(因为它比标准连接快得多)

例如,正确使用 return party_id 列表的子查询,比如 TABLE1 AND TABLE2 AND TABLE3 OR TABLE4 AND TABLE5 然后我可以看到如何编写动态查询生成代码任意组合。

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

我不确定的原因是我猜测 sql 引擎必须遍历每个 table 的所有行,而不管条件是否存在。因此,对查询进行分区可能会导致更多的总循环……这样的推理行得通吗?

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

如果 date/time 范围可能来自 任何 天,那么在每个 table 上设置一个新索引会更有意义,单独 UPDATEDUPDATEDPARTY_ID 的组合。如果有机会,我建议您针对两组索引尝试更新的查询,并查看它们的比较情况。

实现所需的更复杂功能的一种方法可能是对条件表达式求和 - 例如,如果您希望 PARTY_ID in TABLE1 and TABLE2 and 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 表达式中检查的 table 的总数相匹配 - 所以查询在检查 PARTY_ID 是否在前三个 table 中时需要检查 SUMmed CASE 表达式是否等于 3,并且需要检查第二个是否检查最后两个 table 时,表达式等于 2