优化 where 子句中的 SQL 子查询
Optimising SQL sub query in where clause
我有 sql 使用 Oracle SQL Developer 可以正常工作,但我担心更大的实时数据库的性能。
请原谅所有加入 tables,这显示了与保存审计历史记录的 _aud table 和 revision_table 的连接。
select cust.forename, cust.surname
from customer cust
join section_details sd on cust.section = sd.section
where
-- this value is substituted programatically
sd.type = 5 and
(
(select max(rt.timestamp)
from
customer cust_tmp1
join section_details sd on cust_tmp1.section = sd.section
join measure msr on sd.measure = msr.id
join measure_aud msr_a on msr.id = msr_a.id
join revision_table rt on msr_a.rev = rt.id
where
cust_tmp1.id = cust.id and msr.measure = 'Last Contact Date')
>
(select max(rt.timestamp)
from
customer cust_tmp2
join section_details sd on cust_tmp2.section = sd.section
join measure msr on sd.measure = msr.id
join measure_aud msr_a on msr.id = msr_a.id
join revision_table rt on msr_a.rev = rt.id
where
cust_tmp2.id = cust.id and msr.measure = 'Last Order Date')
);
简而言之,如果 'Last Contact Date' 比 'Last Order Date' 更新,我只想检索客户详细信息。我最终检查了一个 select 的 max(timestamp) 是否大于另一个 select.
的 max(timestamp)
一切正常,我得到了我期待的结果。
除了 msr.measure = 'Last Contact Date' 或 'Last Order Date'.
之外,时间戳比较的每一侧都是重复的
我尝试了一些从未真正起作用的替代方案,因为它们导致了多级嵌套子查询,而且我无法传入外部客户记录。
任何进一步的想法将不胜感激。
您可以将其切换为 exists
:
exists (select max(rt.timestamp)
from customer cust_tmp1 join
section_details sd
on cust_tmp1.section = sd.section join
measure msr
on sd.measure = msr.id join
measure_aud msr_a
on msr.id = msr_a.id join
revision_table rt
on msr_a.rev = rt.id
where cust_tmp1.id = cust.id and
msr.measure in ( 'Last Contact Date', 'Last Order Date')
having max(case when msr.measure = 'Last Contact Date' then rt.timestamp end) >
max(case when msr.mesure = 'Last Order Date' then rt.timestamp end)
);
我不确定是否会有很大的性能提升。如果您在数据库中设置了正确的索引,那么您的原始版本应该非常快且可扩展。
您确定需要所有这些联接吗?
具有不同 WHERE 条件的相同查询通常转换为 CASE:
select cust.forename, cust.surname
from customer cust
where
-- this value is substituted programatically
sd.type = 5
and exists
( select *
from
customer cust_tmp1
join section_details sd on cust_tmp1.section = sd.section
join measure msr on sd.measure = msr.id
join measure_aud msr_a on msr.id = msr_a.id
join revision_table rt on msr_a.rev = rt.id
where cust_tmp1.id = cust.id
having max(case when msr.measure = 'Last Contact Date' then rt.timestamp end)
> max(case when msr.measure = 'Last Order Date' then rt.timestamp end)
)
或简化删除子查询:
select cust.forename, cust.surname
from customer cust
join section_details sd on cust_tmp1.section = sd.section
join measure msr on sd.measure = msr.id
join measure_aud msr_a on msr.id = msr_a.id
join revision_table rt on msr_a.rev = rt.id
where
-- this value is substituted programatically
sd.type = 5
group by cust.forename, cust.surname
having max(case when msr.measure = 'Last Contact Date' then rt.timestamp end)
> max(case when msr.measure = 'Last Order Date' then rt.timestamp end)
我尝试了此处发布的解决方案,它们似乎都有效,非常感谢您的回复 - 我之前没有研究过 having 子句。
我添加了所有必需的索引并 运行 解释了所有选项的计划,我的原始查询成本最低。所以我想我会继续使用这个选项。
我有 sql 使用 Oracle SQL Developer 可以正常工作,但我担心更大的实时数据库的性能。
请原谅所有加入 tables,这显示了与保存审计历史记录的 _aud table 和 revision_table 的连接。
select cust.forename, cust.surname
from customer cust
join section_details sd on cust.section = sd.section
where
-- this value is substituted programatically
sd.type = 5 and
(
(select max(rt.timestamp)
from
customer cust_tmp1
join section_details sd on cust_tmp1.section = sd.section
join measure msr on sd.measure = msr.id
join measure_aud msr_a on msr.id = msr_a.id
join revision_table rt on msr_a.rev = rt.id
where
cust_tmp1.id = cust.id and msr.measure = 'Last Contact Date')
>
(select max(rt.timestamp)
from
customer cust_tmp2
join section_details sd on cust_tmp2.section = sd.section
join measure msr on sd.measure = msr.id
join measure_aud msr_a on msr.id = msr_a.id
join revision_table rt on msr_a.rev = rt.id
where
cust_tmp2.id = cust.id and msr.measure = 'Last Order Date')
);
简而言之,如果 'Last Contact Date' 比 'Last Order Date' 更新,我只想检索客户详细信息。我最终检查了一个 select 的 max(timestamp) 是否大于另一个 select.
的 max(timestamp)一切正常,我得到了我期待的结果。
除了 msr.measure = 'Last Contact Date' 或 'Last Order Date'.
之外,时间戳比较的每一侧都是重复的我尝试了一些从未真正起作用的替代方案,因为它们导致了多级嵌套子查询,而且我无法传入外部客户记录。
任何进一步的想法将不胜感激。
您可以将其切换为 exists
:
exists (select max(rt.timestamp)
from customer cust_tmp1 join
section_details sd
on cust_tmp1.section = sd.section join
measure msr
on sd.measure = msr.id join
measure_aud msr_a
on msr.id = msr_a.id join
revision_table rt
on msr_a.rev = rt.id
where cust_tmp1.id = cust.id and
msr.measure in ( 'Last Contact Date', 'Last Order Date')
having max(case when msr.measure = 'Last Contact Date' then rt.timestamp end) >
max(case when msr.mesure = 'Last Order Date' then rt.timestamp end)
);
我不确定是否会有很大的性能提升。如果您在数据库中设置了正确的索引,那么您的原始版本应该非常快且可扩展。
您确定需要所有这些联接吗?
具有不同 WHERE 条件的相同查询通常转换为 CASE:
select cust.forename, cust.surname
from customer cust
where
-- this value is substituted programatically
sd.type = 5
and exists
( select *
from
customer cust_tmp1
join section_details sd on cust_tmp1.section = sd.section
join measure msr on sd.measure = msr.id
join measure_aud msr_a on msr.id = msr_a.id
join revision_table rt on msr_a.rev = rt.id
where cust_tmp1.id = cust.id
having max(case when msr.measure = 'Last Contact Date' then rt.timestamp end)
> max(case when msr.measure = 'Last Order Date' then rt.timestamp end)
)
或简化删除子查询:
select cust.forename, cust.surname
from customer cust
join section_details sd on cust_tmp1.section = sd.section
join measure msr on sd.measure = msr.id
join measure_aud msr_a on msr.id = msr_a.id
join revision_table rt on msr_a.rev = rt.id
where
-- this value is substituted programatically
sd.type = 5
group by cust.forename, cust.surname
having max(case when msr.measure = 'Last Contact Date' then rt.timestamp end)
> max(case when msr.measure = 'Last Order Date' then rt.timestamp end)
我尝试了此处发布的解决方案,它们似乎都有效,非常感谢您的回复 - 我之前没有研究过 having 子句。
我添加了所有必需的索引并 运行 解释了所有选项的计划,我的原始查询成本最低。所以我想我会继续使用这个选项。