我正在尝试编写一个查询,该查询从两个表中提取多列,然后还要查看最近28天内是否还有另一个包含相同类型数据的实例。
我已经使查询正常工作,它看起来像这样:
SELECT
a.col_a
,a.col_b
,a.col_c
,b.col_a
,b.col_b
,CASE WHEN EXSISTS (SELECT a_sub.col_a
FROM a_sub
INNER JOIN b_sub
ON a_sub.x = b_sub.x
WHERE
b.col_a = b_sub.col_a
AND b.col_b <> b_sub.col_b
AND a.date > a_sub.date
AND a.date <= DATEADD(d, 28, a_sub.date)
AND a.col_c = a_sub.col_c
AND (a.col_d IS NULL OR a.col_d <> 7)
AND (a_sub.col_d IS NULL OR a_sub.col_d <> 7)
) THEN 'Yes'
ELSE 'No'
END AS IsRepeat28
FROM a
INNER JOIN b ON a.x = b.x
这不是特别快,但也不会太慢而不会成为问题。问题是我需要重复上述WHEN EXISTS子查询,但要重复21、14、7和1天,并重复5次-查询时间从大约15秒变为大约10分钟。
我还需要调整日期,并标记为“ IsRepeat”的行,还有一个基于“ HasRepeat”的版本,其基于
AND a_sub.date > a.date AND a_sub.date <= DATEADD(d, 28, a.date)
而不是原始的
AND a.date > a_sub.date AND a.date <= DATEADD(d, 28, a_sub.date)
然后这意味着拥有10个这些EXISTS子查询,将花费近45分钟。
我的问题确实是双重的;是否有一种更有效的方式编写此子查询,并且有更好的重复方式,而不是将几乎相同的代码写出10次?
我将产生数据的任何查询称为问题。 SQL仅应用于查询数据。如果您了解自己的流程及其所做的工作,则无需执行计划。
首先,将主投影作为步骤1进行分隔,根据您有多少记录,将其分为临时表或表变量。在生产查询中缓存每个需要的集合,可以将负载大小作为选择计数(*)进行度量。
insert into @mytablevariable values
SELECT
a.col_a,
a.col_b,
a.col_c,
b.col_a,
b.col_b
-- build this column later
FROM a
INNER JOIN b ON a.x = b.x
接下来,缓存该嵌套查询的结果,这样就不会在每次迭代中进行内部联接。
insert into @mysub values
SELECT a_sub.col_a
FROM a_sub
INNER JOIN b_sub
ON a_sub.x = b_sub.x
AND b.col_b <> b_sub.col_b
我们故意制造废物,因此我们可以通过根据您的处理要求对@mysub进行重塑来进行管理。我们的目标是通过以正确的顺序获取正确的数据来消除工作。
在此过程中最突出的是WHERE子句,其中日期字段在日期范围内。
AND a.date > a_sub.date AND a.date <= DATEADD(d, 28, a_sub.date)
自然地,表未按日期列值编制索引,因此,此WHERE比较必须进行全表扫描或我们称为提取器的提取。提取器从集合中提取一部分数据(子集)。我们始终希望将提取过程减少到一遍,这只有在完成对提取器的组织标准时才能完成。
首先,通过外部@mytablevariable查询中所需的日期值范围来最小化@mysub提取器结果的大小。
insert into @mysub values
SELECT a_sub.col_a
FROM a_sub
INNER JOIN b_sub
ON a_sub.x = b_sub.x
AND b.col_b <> b_sub.col_b
and a_sub.date <= DATEADD(d, 28, select min(a.date) from @mytablevariable)
and a_sub.date > (select max(a.date) from @mytablevariable)
然后,您可以将@mysub投影到您的21天子集中,将其他较小的子集再次投影。对于WHERE子句的其余部分,使用要比较的列扩展@mysub。要构建最终产品,请从第一个表中选择所有内容,并按以下方式对每个记录进行一次查找。
select
*,
case
when b.col_a in (select col_a from @mysub28) then 'Yes'
else 'No'
end as IsRepeat28,
case
when b.col_a in (select col_a from @mysub21) then 'Yes'
else 'No'
end as IsRepeat21
-- rinse, repeat
from
@mytablevariable
[每当您有生产流程时,请分离出组件并按照提取器的选择标准进行操作,以使它们只通过一遍。