Oracle SQL - 有效地查找两个日期之间的最后有效更改
Oracle SQL - Finding the last date effective change between two dates efficiently
我经常使用以下 Oracle SQL 查询来查找两个日期之间的最后日期有效更改,但效率不高(完整 table 扫描)。 per_all_people_f
上的主键是 person_id, effective_start_date, effective_end_date
.
基本上对于用户名(不存储日期有效更改),我想找到与该用户相关的员工的详细信息。然而,员工更改是有效存储日期的,因此我需要找到起始日期和截止日期参数之间的最后日期有效更改。
是否有适用于两个日期之间的 Oracle 索引?有什么技巧可以用来将现有的主键索引与开始日期和结束日期一起使用吗?我如何编写查询才能更有效率?我写的几乎所有查询都会用到这个逻辑。
select fu.user_name, papf.employee_number
from fnd_user fu
left outer join
(
select papf2.person_id,
max(papf2.effective_start_date) max_effective_start_date
from per_all_people_f papf2
where papf2.effective_start_date between :P_FROM and :P_TO
group by papf2.person_id
) papf3
on papf3.person_id = fu.employee_id
left outer join per_all_people_f papf
on papf.person_id = fu.employee_id
and papf.effective_start_date = papf3.max_effective_start_date
想想看,Oracle 一定在主键索引中的 effective_start_date
和 effective_end_date
上浪费了很多磁盘 space,因为它们只有一次会被使用如果您知道 effective_start_date
.
的日期
没有必要加入per_all_people_f
两次,试试ROW_NUMBER。
select fu.user_name, papf3.employee_number
from fnd_user fu
left outer join
(
select papf2.person_id, papf2.employee_number,
row_number() -- latest date first
over (partition by papf2.person_id
order by effective_start_date desc ) as rn
from per_all_people_f papf2
where papf2.effective_start_date between :P_FROM and :P_TO
) papf3
on papf3.person_id = fu.employee_id
and papf3.rn = 1
这是另一个选项:
select
fu.user_name,
papf.employee_number
from
fnd_user fu,
(
select distinct
papf.person_id,
min(papf.employee_number) keep (dense_rank last order by papf.effective_start_date) over (partition by papf.person_id) employee_number
from
per_all_people_f papf
where
papf.effective_start_date between :p_from and :p_to
) papf
where
fu.employee_id=papf.person_id(+)
关于性能的注意事项:如果您想列出特定日期范围内的所有用户及其对应的可能的人员记录更改,则对两个完整数据集进行散列连接可能是最佳选择。
如果您有大量员工,但其中没有多少人拥有应用程序用户,则 /*+ push_pred(papf)*/
建议的索引访问可能会更好。如果日期范围较小且有选择性,请在 effective_start_date 上创建索引,让优化器对 fnd_user 和该自定义索引获取的 per_all_people_f 记录进行散列连接。
要判断哪个选项最好,不要看执行时间,打开自动跟踪并检查哪个选项具有最低的IO。
我经常使用以下 Oracle SQL 查询来查找两个日期之间的最后日期有效更改,但效率不高(完整 table 扫描)。 per_all_people_f
上的主键是 person_id, effective_start_date, effective_end_date
.
基本上对于用户名(不存储日期有效更改),我想找到与该用户相关的员工的详细信息。然而,员工更改是有效存储日期的,因此我需要找到起始日期和截止日期参数之间的最后日期有效更改。
是否有适用于两个日期之间的 Oracle 索引?有什么技巧可以用来将现有的主键索引与开始日期和结束日期一起使用吗?我如何编写查询才能更有效率?我写的几乎所有查询都会用到这个逻辑。
select fu.user_name, papf.employee_number
from fnd_user fu
left outer join
(
select papf2.person_id,
max(papf2.effective_start_date) max_effective_start_date
from per_all_people_f papf2
where papf2.effective_start_date between :P_FROM and :P_TO
group by papf2.person_id
) papf3
on papf3.person_id = fu.employee_id
left outer join per_all_people_f papf
on papf.person_id = fu.employee_id
and papf.effective_start_date = papf3.max_effective_start_date
想想看,Oracle 一定在主键索引中的 effective_start_date
和 effective_end_date
上浪费了很多磁盘 space,因为它们只有一次会被使用如果您知道 effective_start_date
.
没有必要加入per_all_people_f
两次,试试ROW_NUMBER。
select fu.user_name, papf3.employee_number
from fnd_user fu
left outer join
(
select papf2.person_id, papf2.employee_number,
row_number() -- latest date first
over (partition by papf2.person_id
order by effective_start_date desc ) as rn
from per_all_people_f papf2
where papf2.effective_start_date between :P_FROM and :P_TO
) papf3
on papf3.person_id = fu.employee_id
and papf3.rn = 1
这是另一个选项:
select
fu.user_name,
papf.employee_number
from
fnd_user fu,
(
select distinct
papf.person_id,
min(papf.employee_number) keep (dense_rank last order by papf.effective_start_date) over (partition by papf.person_id) employee_number
from
per_all_people_f papf
where
papf.effective_start_date between :p_from and :p_to
) papf
where
fu.employee_id=papf.person_id(+)
关于性能的注意事项:如果您想列出特定日期范围内的所有用户及其对应的可能的人员记录更改,则对两个完整数据集进行散列连接可能是最佳选择。
如果您有大量员工,但其中没有多少人拥有应用程序用户,则 /*+ push_pred(papf)*/
建议的索引访问可能会更好。如果日期范围较小且有选择性,请在 effective_start_date 上创建索引,让优化器对 fnd_user 和该自定义索引获取的 per_all_people_f 记录进行散列连接。
要判断哪个选项最好,不要看执行时间,打开自动跟踪并检查哪个选项具有最低的IO。