使用 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 上设置一个新索引会更有意义,单独 UPDATED
或 UPDATED
和 PARTY_ID
的组合。如果有机会,我建议您针对两组索引尝试更新的查询,并查看它们的比较情况。
实现所需的更复杂功能的一种方法可能是对条件表达式求和 - 例如,如果您希望 PARTY_ID
in TABLE1
and TABLE2
and TABLE3
或 TABLE4
和 TABLE5
:
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。
这是一项与市场细分分析相关的工作,运行我一天想几次。
查询类型,我将解释,需要在 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 上设置一个新索引会更有意义,单独 UPDATED
或 UPDATED
和 PARTY_ID
的组合。如果有机会,我建议您针对两组索引尝试更新的查询,并查看它们的比较情况。
实现所需的更复杂功能的一种方法可能是对条件表达式求和 - 例如,如果您希望 PARTY_ID
in TABLE1
and TABLE2
and TABLE3
或 TABLE4
和 TABLE5
:
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。